Subversion Repositories seema-scanner

Rev

Rev 163 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
161 raly 1
#include "AlgorithmGrayCodeMax.h"
2
#include <cmath>
3
#include "cvtools.h"
4
 
5
#ifndef log2f
6
#define log2f(x) (log(x)/log(2.0))
7
#endif
8
 
9
//using namespace std;
10
 
163 raly 11
namespace ggmax {
12
 
161 raly 13
/*
14
 * The purpose of this function is to convert an unsigned
15
 * binary number to reflected binary Gray code.
16
 *
17
 * The operator >> is shift right. The operator ^ is exclusive or.
18
 * Source: http://en.wikipedia.org/wiki/Gray_code
19
 */
20
static unsigned int binaryToGray(unsigned int num) {
21
    return (num >> 1) ^ num;
22
}
23
 
24
/*
25
 * From Wikipedia: http://en.wikipedia.org/wiki/Gray_code
26
 * The purpose of this function is to convert a reflected binary
27
 * Gray code number to a binary number.
28
 */
29
static unsigned int grayToBinary(unsigned int num){
30
    unsigned int mask;
31
    for(mask = num >> 1; mask != 0; mask = mask >> 1)
32
        num = num ^ mask;
33
    return num;
34
}
35
 
36
/*
37
 * Return the Nth bit of an unsigned integer number
38
 */
39
static bool getBit(int decimal, int N){
40
 
41
    return decimal & 1 << (N-1);
42
}
43
 
167 jakw 44
///*
45
// * Return the number of bits set in an integer
46
// */
47
//static int countBits(int n) {
48
//  unsigned int c; // c accumulates the total bits set in v
49
//  for (c = 0; n>0; c++)
50
//    n &= n - 1; // clear the least significant bit set
51
//  return c;
52
//}
161 raly 53
 
54
/*
55
 * Return the position of the least significant bit that is set
56
 */
57
static int leastSignificantBitSet(int x){
58
  if(x == 0)
59
      return 0;
60
 
61
  int val = 1;
62
  while(x>>=1)
63
      val++;
64
 
65
  return val;
66
}
67
 
68
//static int get_bit(int decimal, int N){
69
 
70
//    // Shifting the 1 for N-1 bits
71
//    int constant = 1 << (N-1);
72
 
73
//    // If the bit is set, return 1
74
//    if( decimal & constant )
75
//        return 1;
76
//    else
77
//        return 0;
78
//}
79
 
80
static inline unsigned int powi(int num, unsigned int exponent){
81
 
82
    if(exponent == 0)
83
        return 1;
84
 
85
    float res = num;
86
    for(unsigned int i=0; i<exponent-1; i++)
87
        res *= num;
88
 
89
    return res;
90
}
91
 
92
static inline unsigned int twopowi(unsigned int exponent){
93
 
94
    return 1 << exponent;
95
}
96
 
163 raly 97
bool sortingLarger(cv::Vec4i i,cv::Vec4i j){ return (i[3]<j[3]);}
98
bool sortingEqual(cv::Vec4i i,cv::Vec4i j){ return (i[3]==j[3]);}
99
void getEdgeLabels(const cv::Mat& scanLine, int Nbits, std::vector<cv::Vec4i>& edges){
100
 
101
    int nCols = scanLine.cols;
102
    const int *data = scanLine.ptr<const int>(0);
103
 
104
    int labelLeft;
105
    int labelRight = data[0];
106
 
107
    // collect edges
108
    for(int col=1; col<nCols; col++){
109
 
110
        labelLeft = labelRight;
111
        labelRight = data[col];
112
 
113
        // labels need to be non-background, and differ in exactly one bit
114
        if(labelLeft != -1 && labelRight != -1 && (ggmax::grayToBinary(labelRight) == ggmax::grayToBinary(labelLeft)+1)){
115
            int orderingRelation = (labelLeft << Nbits) + labelRight;
116
            // store left label column
117
            edges.push_back(cv::Vec4i(col-1, labelLeft, labelRight, orderingRelation));
118
        }
119
    }
120
 
121
    // sort
122
    std::sort(edges.begin(), edges.end(), sortingLarger);
123
 
124
    // remove duplicates
125
    std::vector<cv::Vec4i>::iterator it;
126
    it = std::unique(edges.begin(), edges.end(), sortingEqual);
127
    edges.resize(std::distance(edges.begin(),it));
128
}
129
} // End ggmax namespace
130
 
161 raly 131
// Algorithm
132
AlgorithmGrayCodeMax::AlgorithmGrayCodeMax(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
133
 
134
    Nbits = ceilf(log2f((float)screenCols)) - 1;
135
    N = 2 + Nbits*2;
136
 
137
    // all on pattern
138
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
139
    patterns.push_back(allOn);
140
 
141
    // all off pattern
142
    cv::Mat allOff(1, screenCols, CV_8UC3, cv::Scalar::all(0));
143
    patterns.push_back(allOff);
144
 
145
 
146
    // horizontally encoding patterns
147
    for(unsigned int p=0; p<Nbits; p++){
148
        cv::Mat pattern(1, screenCols, CV_8UC3);
149
        cv::Mat patternInv(1, screenCols, CV_8UC3);
150
 
151
        for(unsigned int j=0; j<screenCols; j++){
152
 
163 raly 153
            unsigned int jGray = ggmax::binaryToGray(j);
161 raly 154
            // Amplitude of channels
163 raly 155
            int bit = (int)ggmax::getBit(jGray, Nbits-p+1);
161 raly 156
            pattern.at<cv::Vec3b>(0,j) = cv::Vec3b(255.0*bit,255.0*bit,255.0*bit);
157
            int invBit = bit^1;
158
            patternInv.at<cv::Vec3b>(0,j) = cv::Vec3b(255.0*invBit,255.0*invBit,255.0*invBit);
159
        }
160
        patterns.push_back(pattern);
161
        patterns.push_back(patternInv);
162
    }
163
 
164
 
165
}
166
 
167
cv::Mat AlgorithmGrayCodeMax::getEncodingPattern(unsigned int depth){
168
    return patterns[depth];
169
}
170
 
167 jakw 171
//static cv::Vec3b getColorSubpix(const cv::Mat& img, cv::Point2f pt){
172
//    assert(!img.empty());
173
//    assert(img.channels() == 3);
161 raly 174
 
167 jakw 175
//    int x = (int)pt.x;
176
//    int y = (int)pt.y;
161 raly 177
 
167 jakw 178
//    int x0 = cv::borderInterpolate(x,   img.cols, cv::BORDER_REFLECT_101);
179
//    int x1 = cv::borderInterpolate(x+1, img.cols, cv::BORDER_REFLECT_101);
180
//    int y0 = cv::borderInterpolate(y,   img.rows, cv::BORDER_REFLECT_101);
181
//    int y1 = cv::borderInterpolate(y+1, img.rows, cv::BORDER_REFLECT_101);
161 raly 182
 
167 jakw 183
//    float a = pt.x - (float)x;
184
//    float c = pt.y - (float)y;
161 raly 185
 
167 jakw 186
//    uchar b = (uchar)cvRound((img.at<cv::Vec3b>(y0, x0)[0] * (1.f - a) + img.at<cv::Vec3b>(y0, x1)[0] * a) * (1.f - c)
187
//                           + (img.at<cv::Vec3b>(y1, x0)[0] * (1.f - a) + img.at<cv::Vec3b>(y1, x1)[0] * a) * c);
188
//    uchar g = (uchar)cvRound((img.at<cv::Vec3b>(y0, x0)[1] * (1.f - a) + img.at<cv::Vec3b>(y0, x1)[1] * a) * (1.f - c)
189
//                           + (img.at<cv::Vec3b>(y1, x0)[1] * (1.f - a) + img.at<cv::Vec3b>(y1, x1)[1] * a) * c);
190
//    uchar r = (uchar)cvRound((img.at<cv::Vec3b>(y0, x0)[2] * (1.f - a) + img.at<cv::Vec3b>(y0, x1)[2] * a) * (1.f - c)
191
//                           + (img.at<cv::Vec3b>(y1, x0)[2] * (1.f - a) + img.at<cv::Vec3b>(y1, x1)[2] * a) * c);
161 raly 192
 
167 jakw 193
//    return cv::Vec3b(b, g, r);
194
//}
161 raly 195
 
196
void AlgorithmGrayCodeMax::get3DPoints(SMCalibrationParameters calibration, const std::vector<cv::Mat>& frames0, const std::vector<cv::Mat>& frames1, std::vector<cv::Point3f>& Q, std::vector<cv::Vec3b>& color){
197
 
198
    assert(frames0.size() == N);
199
    assert(frames1.size() == N);
200
 
201
//    for(int i=0; i<1920; i++){
202
//        std::cout << i << " " << binaryToGray(i) << " " << grayToBinary(binaryToGray(i)) << std::endl;
203
//    }
204
 
205
    int frameRows = frames0[0].rows;
206
    int frameCols = frames0[0].cols;
207
 
208
    // rectifying homographies (rotation+projections)
209
    cv::Size frameSize(frameCols, frameRows);
210
    cv::Mat R, T;
211
    // stereoRectify segfaults unless R is double precision
212
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
213
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
214
    cv::Mat R0, R1, P0, P1, QRect;
215
    cv::stereoRectify(calibration.K0, calibration.k0, calibration.K1, calibration.k1, frameSize, R, T, R0, R1, P0, P1, QRect, 0);
216
 
217
//    std::cout << "R0" << std::endl << R0 << std::endl;
218
//    std::cout << "P0" << std::endl << P0 << std::endl;
219
//    std::cout << "R1" << std::endl << R1 << std::endl;
220
//    std::cout << "P1" << std::endl << P1 << std::endl;
221
 
222
    // interpolation maps
223
    cv::Mat map0X, map0Y, map1X, map1Y;
224
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0, R0, P0, frameSize, CV_32F, map0X, map0Y);
225
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1, R1, P1, frameSize, CV_32F, map1X, map1Y);
226
 
227
    // gray-scale and remap (Rasmus has adjusted here)
228
    std::vector<cv::Mat> frames0Rect(N);
229
    std::vector<cv::Mat> frames1Rect(N);
163 raly 230
    for(size_t i=0; i<N; i++){
231
        cv::Mat temp;
161 raly 232
        cv::Mat temp_col;
233
        cv::cvtColor(frames0[i], temp_col, CV_BayerBG2RGB);
234
		std::vector<cv::Mat> channels(3);
163 raly 235
        cv::split(temp_col, channels);
236
        temp = cv::max(channels[2], cv::max(channels[1], channels[0])); // Calculate max of the three channels
161 raly 237
        cv::remap(temp, frames0Rect[i], map0X, map0Y, CV_INTER_LINEAR);
238
 
239
        cv::cvtColor(frames1[i], temp_col, CV_BayerBG2RGB);
163 raly 240
        channels.clear();
241
        cv::split(temp_col, channels);
242
        temp = cv::max(channels[2], cv::max(channels[1], channels[0]));
161 raly 243
        cv::remap(temp, frames1Rect[i], map1X, map1Y, CV_INTER_LINEAR);
244
    }
245
 
246
 
247
//    cvtools::writeMat(frames0Rect[0], "frames0Rect_0.mat", "frames0Rect_0");
248
//    cvtools::writeMat(frames0[0], "frames0_0.mat", "frames0_0");
249
 
250
//    cvtools::writeMat(frames0Rect[22], "frames0Rect_22.mat", "frames0Rect_22");
251
//    cvtools::writeMat(frames0Rect[23], "frames0Rect_23.mat", "frames0Rect_23");
252
 
253
//    cv::imwrite("frames0[0].png", frames0[0]);
254
//    cv::imwrite("frames0Rect[0].png", frames0Rect[0]);
255
 
256
//    cv::imwrite("frames1[0].png", frames1[0]);
257
//    cv::imwrite("frames1Rect[0].png", frames1Rect[0]);
258
 
259
    // color debayer and remap
260
    cv::Mat color0Rect, color1Rect;
261
//    frames0[0].convertTo(color0Rect, CV_8UC1, 1.0/256.0);
262
    cv::cvtColor(frames0[0], color0Rect, CV_BayerBG2RGB);
263
    cv::remap(color0Rect, color0Rect, map0X, map0Y, CV_INTER_LINEAR);
264
 
265
//    frames1[0].convertTo(color1Rect, CV_8UC1, 1.0/256.0);
266
    cv::cvtColor(frames1[0], color1Rect, CV_BayerBG2RGB);
267
    cv::remap(color1Rect, color1Rect, map1X, map1Y, CV_INTER_LINEAR);
268
 
269
    int frameRectRows = frames0Rect[0].rows;
270
    int frameRectCols = frames0Rect[0].cols;
271
 
272
//cvtools::writeMat(frames0Rect[0], "frames0Rect_0.mat", "frames0Rect_0");
273
//cvtools::writeMat(frames0Rect[1], "frames0Rect_1.mat", "frames0Rect_1");
274
//cvtools::writeMat(frames0Rect[20], "frames0Rect_20.mat", "frames0Rect_20");
275
//cvtools::writeMat(frames0Rect[21], "frames0Rect_21.mat", "frames0Rect_21");
276
 
277
    // occlusion masks
278
    cv::Mat occlusion0Rect, occlusion1Rect;
279
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0Rect);
280
    occlusion0Rect = (occlusion0Rect > 10) & (occlusion0Rect < 250);
281
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1Rect);
282
    occlusion1Rect = (occlusion1Rect > 10) & (occlusion1Rect < 250);
283
 
284
    // erode occlusion masks
285
    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(2,2));
286
    cv::erode(occlusion0Rect, occlusion0Rect, strel);
287
    cv::erode(occlusion1Rect, occlusion1Rect, strel);
288
 
289
//cvtools::writeMat(frames0Rect[0], "frames0Rect_0.mat", "frames0Rect_0");
290
//cvtools::writeMat(frames0Rect[1], "frames0Rect_1.mat", "frames0Rect_1");
291
//cvtools::writeMat(frames0Rect[20], "frames0Rect_20.mat", "frames0Rect_20");
292
//cvtools::writeMat(frames0Rect[21], "frames0Rect_21.mat", "frames0Rect_21");
293
 
294
//    // correct for projector inversion error
295
//    cv::Mat W;
296
//    cv::add(frames0Rect[0], frames0Rect[1], W, cv::noArray(), CV_32F);
297
//    for(int i=2; i<N; i+=2){
298
//        cv::Mat S, E;
299
//        cv::add(frames0Rect[i], frames0Rect[i+1], S, cv::noArray(), CV_32F);
300
//        cv::subtract(W, S, E, cv::noArray(), CV_32F);
301
//        E *= 0.5;
302
//        cv::add(frames0Rect[i], E, frames0Rect[i], cv::noArray(), CV_16UC1);
303
//        cv::add(frames0Rect[i+1], E, frames0Rect[i+1], cv::noArray(), CV_16UC1);
304
//    }
305
 
306
 
307
//    // correct for texture modulation and ambient
308
//    cv::Mat A0 = frames0Rect[1];
309
//    cv::Mat M0 = frames0Rect[0]-frames0Rect[1];
310
////cvtools::writeMat(A0, "A0.mat", "A0");
311
////cvtools::writeMat(M0, "M0.mat", "M0");
312
////cvtools::writeMat(frames0Rect[20], "frames0Rect_20.mat", "frames0Rect_20");
313
////cvtools::writeMat(frames0Rect[21], "frames0Rect_21.mat", "frames0Rect_21");
314
//    cv::divide(256.0, M0, M0, CV_32F);
315
//    cv::Mat A1 = frames1Rect[1];
316
//    cv::Mat M1 = frames1Rect[0]-frames1Rect[1];
317
//    cv::divide(256.0, M1, M1, CV_32F);
318
 
319
//    for(int i=2; i<N; i++){
320
//        cv::multiply(frames0Rect[i]-A0, M0, frames0Rect[i], 1.0, CV_8UC1);
321
//        cv::multiply(frames1Rect[i]-A1, M1, frames1Rect[i], 1.0, CV_8UC1);
322
//    }
323
 
324
//cvtools::writeMat(frames0Rect[22], "frames0Rect_22.mat", "frames0Rect_22");
325
//cvtools::writeMat(frames0Rect[23], "frames0Rect_23.mat", "frames0Rect_23");
326
 
327
//cvtools::writeMat(occlusion0Rect, "occlusion0Rect.mat", "occlusion0Rect");
328
//cvtools::writeMat(occlusion1Rect, "occlusion1Rect.mat", "occlusion1Rect");
329
 
330
    // decode patterns
331
    cv::Mat code0Rect(frameRectRows, frameRectCols, CV_32S, cv::Scalar(0));
332
    cv::Mat code1Rect(frameRectRows, frameRectCols, CV_32S, cv::Scalar(0));
333
 
334
    // into gray code
167 jakw 335
    for(unsigned int i=0; i<Nbits; i++){
161 raly 336
        cv::Mat temp, bit0, bit1;
337
 
338
        cv::compare(frames0Rect[i*2+2], frames0Rect[i*2+3], temp, cv::CMP_GT);
339
        temp.convertTo(bit0, CV_32S, 1.0/255.0);
163 raly 340
        cv::add(code0Rect, bit0*ggmax::twopowi(Nbits-i-1), code0Rect, cv::noArray(), CV_32S);
161 raly 341
 
342
        cv::compare(frames1Rect[i*2+2], frames1Rect[i*2+3], temp, cv::CMP_GT);
343
        temp.convertTo(bit1, CV_32S, 1.0/255.0);
163 raly 344
        cv::add(code1Rect, bit1*ggmax::twopowi(Nbits-i-1), code1Rect, cv::noArray(), CV_32S);
161 raly 345
    }
346
 
347
//cvtools::writeMat(code0Rect, "code0Rect.mat", "code0Rect");
348
//cvtools::writeMat(code1Rect, "code1Rect.mat", "code1Rect");
349
 
350
 
351
//    // convert to standard binary
352
//    cv::Mat code0Binary(code0Rect.rows, code0Rect.cols, CV_32F);
353
//    cv::Mat code1Binary(code1Rect.rows, code1Rect.cols, CV_32F);
354
//    for(int r=0; r<frameRectRows; r++){
355
//        for(int c=0; c<frameRectCols; c++){
356
//            if(code0Rect.at<int>(r,c) != -1)
357
//                code0Binary.at<float>(r,c) = grayToBinary(code0Rect.at<int>(r,c));
358
//            if(code1Rect.at<int>(r,c) != -1)
359
//                code1Binary.at<float>(r,c) = grayToBinary(code1Rect.at<int>(r,c));
360
//        }
361
//    }
362
 
363
//cvtools::writeMat(code0Binary, "code0Binary.mat", "code0Binary");
364
//cvtools::writeMat(code1Binary, "code1Binary.mat", "code1Binary");
365
 
366
//    // threshold on vertical discontinuities (due to imperfect rectification)
367
//    cv::Mat edges0;
368
//    cv::Sobel(code0Binary, edges0, -1, 0, 1, 5);
369
//    occlusion0Rect = occlusion0Rect & (abs(edges0) < 50);
370
 
371
//    cv::Mat edges1;
372
//    cv::Sobel(code1Binary, edges1, -1, 0, 1, 5);
373
//    occlusion1Rect = occlusion1Rect & (abs(edges1) < 50);
374
 
375
//cvtools::writeMat(edges0, "edges0.mat", "edges0");
376
//cvtools::writeMat(edges1, "edges1.mat", "edges1");
377
 
378
    // set occluded pixels to -1
379
    for(int r=0; r<frameRectRows; r++){
380
        for(int c=0; c<frameRectCols; c++){
381
            if(occlusion0Rect.at<unsigned char>(r,c) == 0)
382
                code0Rect.at<int>(r,c) = -1;
383
            if(occlusion1Rect.at<unsigned char>(r,c) == 0)
384
                code1Rect.at<int>(r,c) = -1;
385
        }
386
    }
387
 
388
//    cvtools::writeMat(code0Rect, "code0Rect.mat", "code0Rect");
389
//    cvtools::writeMat(code1Rect, "code1Rect.mat", "code1Rect");
390
 
391
    // matching
392
    std::vector<cv::Vec2f> q0Rect, q1Rect;
393
    for(int row=0; row<frameRectRows; row++){
394
 
395
        // edge data structure containing [floor(column), labelLeft, labelRight, orderingRelation]
396
        std::vector<cv::Vec4i> edges0, edges1;
397
 
398
        // sorted, unique edges
163 raly 399
        ggmax::getEdgeLabels(code0Rect.row(row), Nbits, edges0);
400
        ggmax::getEdgeLabels(code1Rect.row(row), Nbits, edges1);
161 raly 401
 
402
        // match edges
403
        std::vector<cv::Vec4i> matchedEdges0, matchedEdges1;
167 jakw 404
        unsigned int i=0, j=0;
161 raly 405
        while(i<edges0.size() && j<edges1.size()){
406
 
407
            if(edges0[i][3] == edges1[j][3]){
408
                matchedEdges0.push_back(edges0[i]);
409
                matchedEdges1.push_back(edges1[j]);
410
                i += 1;
411
                j += 1;
412
            } else if(edges0[i][3] < edges1[j][3]){
413
                i += 1;
414
            } else if(edges0[i][3] > edges1[j][3]){
415
                j += 1;
416
            }
417
        }
418
 
419
        // crude subpixel refinement
420
        // finds the intersection of linear interpolants in the positive/negative pattern
167 jakw 421
        for(unsigned int i=0; i<matchedEdges0.size(); i++){
161 raly 422
 
163 raly 423
            int level = Nbits - ggmax::leastSignificantBitSet(matchedEdges0[i][1]^matchedEdges0[i][2]);
161 raly 424
 
425
            // refine for camera 0
426
            float c0 = matchedEdges0[i][0];
427
            float c1 = c0+1;
428
 
429
            float pos0 = frames0Rect[2*level+2].at<unsigned char>(row, c0);
430
            float pos1 = frames0Rect[2*level+2].at<unsigned char>(row, c1);
431
            float neg0 = frames0Rect[2*level+3].at<unsigned char>(row, c0);
432
            float neg1 = frames0Rect[2*level+3].at<unsigned char>(row, c1);
433
 
434
            float col = c0 + (pos0 - neg0)/(neg1 - neg0 - pos1 + pos0);
435
            q0Rect.push_back(cv::Point2f(col, row));
436
 
437
            // refine for camera 1
438
            c0 = matchedEdges1[i][0];
439
            c1 = c0+1;
440
 
441
            pos0 = frames1Rect[2*level+2].at<unsigned char>(row, c0);
442
            pos1 = frames1Rect[2*level+2].at<unsigned char>(row, c1);
443
            neg0 = frames1Rect[2*level+3].at<unsigned char>(row, c0);
444
            neg1 = frames1Rect[2*level+3].at<unsigned char>(row, c1);
445
 
446
            col = c0 + (pos0 - neg0)/(neg1 - neg0 - pos1 + pos0);
447
            q1Rect.push_back(cv::Point2f(col, row));
448
 
449
        }
450
 
451
    }
452
 
453
    int nMatches = q0Rect.size();
454
 
455
    if(nMatches < 1){
456
        Q.resize(0);
457
        color.resize(0);
458
 
459
        return;
460
    }
461
 
462
    // retrieve color information (at integer coordinates)
463
    color.resize(nMatches);
464
    for(int i=0; i<nMatches; i++){
465
 
466
        cv::Vec3b c0 = color0Rect.at<cv::Vec3b>(q0Rect[i][1], q0Rect[i][0]);
467
        cv::Vec3b c1 = color1Rect.at<cv::Vec3b>(q1Rect[i][1], q1Rect[i][0]);
468
//        cv::Vec3b c0 = getColorSubpix(color0Rect, q0Rect[i]);
469
//        cv::Vec3b c1 = getColorSubpix(color1Rect, q0Rect[i]);
470
 
471
        color[i] = 0.5*c0 + 0.5*c1;
472
    }
473
 
474
    // triangulate points
475
    cv::Mat QMatHomogenous, QMat;
476
//    cv::Mat C0 = P0.clone();
477
//    cv::Mat C1 = P1.clone();
478
//    C0.colRange(0, 3) = C0.colRange(0, 3)*R0;
479
//    C1.colRange(0, 3) = C1.colRange(0, 3)*R1.t();
480
    cv::triangulatePoints(P0, P1, q0Rect, q1Rect, QMatHomogenous);
481
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
482
 
483
    // undo rectifying rotation
484
    cv::Mat R0Inv;
485
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
486
    QMat = R0Inv*QMat;
487
 
488
    cvtools::matToPoints3f(QMat, Q);
489
 
490
}