Subversion Repositories seema-scanner

Rev

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

Rev Author Line No. Line
192 jakw 1
//
2
// Embedded Phase Shifting
3
//
4
// This implementation follows "Moreno, Son, Taubin: Embedded Phase Shifting: Robust Phase Shifting with Embedded Signals, CVPR 2015"
5
//
6
//
7
 
8
#include "AlgorithmPhaseShiftEmbedded.h"
9
#include <math.h>
10
 
11
#include "cvtools.h"
12
#include "algorithmtools.h"
13
 
14
// Number of frequencies
193 jakw 15
static const int M = 4;
192 jakw 16
 
193 jakw 17
// Embedded periods (product of these must be greater than screenCols)
18
static const float Tm[M] = {16, 8, 8, 8};
192 jakw 19
 
20
// Number of patterns at each frequency
193 jakw 21
static const int Nm[M] = {3, 3, 3, 3};
192 jakw 22
 
23
 
24
AlgorithmPhaseShiftEmbedded::AlgorithmPhaseShiftEmbedded(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
25
 
26
    // Set N
27
    N = 2;
28
    for(int m=0; m<M; m++)
29
        N += Nm[m];
30
 
31
    // all on pattern
32
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
33
    patterns.push_back(allOn);
34
 
35
    // all off pattern
36
    cv::Mat allOff(1, screenCols, CV_8UC3, cv::Scalar::all(0));
37
    patterns.push_back(allOff);
38
 
39
    // Precompute encoded patterns
40
    const float pi = M_PI;
41
 
193 jakw 42
    // Compute embedded frequencies
43
    float Fm[M];
44
    for(int m=0; m<M; m++){
45
        Fm[m] = 1.0;
46
        for(int i=0; i<=m; i++)
47
            Fm[m] *= 1.0/Tm[i];
48
    }
49
 
50
    // Compute pattern frequencies
51
    float fm[M];
52
    for(int m=0; m<M; m++)
53
        fm[m] = Fm[0];
54
    for(int m=1; m<M; m++)
55
        fm[m] += Fm[m];
56
 
57
    for(int m=0; m<M; m++)
58
        std::cout << fm[m] << std::endl;
59
 
192 jakw 60
    // Encoding patterns
61
    for(int m=0; m<M; m++){
62
        int nSteps = Nm[m];
193 jakw 63
        float frequency = fm[m];
192 jakw 64
        for(unsigned int i=0; i<nSteps; i++){
193 jakw 65
            float phase = 2.0*pi/std::max(nSteps, 3) * i;
192 jakw 66
            float pitch = 1.0/frequency;
67
            cv::Mat patternI(1,1,CV_8U);
68
            patternI = computePhaseVector(screenCols, phase, pitch);
69
            patterns.push_back(patternI.t());
70
        }
71
    }
72
 
73
}
74
 
75
cv::Mat AlgorithmPhaseShiftEmbedded::getEncodingPattern(unsigned int depth){
76
    return patterns[depth];
77
}
78
 
193 jakw 79
static void decodeEmbeddedPS(const std::vector<cv::Mat> &frames, cv::Mat &up, cv::Mat &upRange, float screenCols){
192 jakw 80
 
81
    const int N = frames.size();
82
 
83
    // Construct shift matrix
193 jakw 84
    cv::Mat A(N, 1 + 2*M, CV_32F);
85
    A.col(0).setTo(1.0);
192 jakw 86
 
87
    int rowBegin = 0;
88
    for(int m=0; m<M; m++){
89
 
90
        int nSteps = Nm[m];
91
 
92
        cv::Mat Am(nSteps, 2, CV_32F);
93
 
94
        for(unsigned int i=0; i<nSteps; i++){
193 jakw 95
            float phase = 2.0*CV_PI/std::max(nSteps, 3) * i;
192 jakw 96
 
97
            Am.at<float>(i, 0) = std::cos(phase);
98
            Am.at<float>(i, 1) = -std::sin(phase);
99
        }
100
 
101
        // Copy into the A matrix
102
        Am.copyTo(A.rowRange(rowBegin, rowBegin+nSteps).colRange(1+2*m, 1+2*(m+1)));
103
        rowBegin += nSteps;
104
    }
193 jakw 105
    //std::cout << A << std::endl << std::endl;
192 jakw 106
 
107
    int frameRows = frames[0].rows;
108
    int frameCols = frames[0].cols;
109
 
110
    // DC-offset
111
    cv::Mat O(frameRows, frameCols, CV_32F);
112
 
113
    // Relative phase maps
114
    std::vector<cv::Mat> phim;
115
    for(int i=0; i<N; i++)
116
        phim.push_back(cv::Mat(frameRows, frameCols, CV_32F));
117
 
118
    // Solve for relative phase values
119
    for(int row=0; row<frameRows; row++){
120
        for(int col=0; col<frameCols; col++){
121
 
122
            // Measurement vector
123
            cv::Mat r(N, 1, CV_32F);
124
            for(int i=0; i<N; i++)
193 jakw 125
                r.at<float>(i) = frames[i].at<uchar>(row, col);
192 jakw 126
 
127
            // Solve
128
            cv::Mat u; //[o, a cos1, a sin1, a cos2, a sin2, ...]
193 jakw 129
            cv::solve(A, r, u, cv::DECOMP_SVD);
192 jakw 130
 
131
            for(int m=0; m<M; m++)
132
                phim[m].at<float>(row, col) = std::atan2(u.at<float>(m*2+1), u.at<float>(m*2+2));
133
 
134
            O.at<float>(row, col) = u.at<float>(0);
135
        }
136
 
137
    }
138
 
193 jakw 139
    #if 0
140
        for(int i=0; i<N; i++)
141
            cvtools::writeMat(frames[i], QString("frames_%1.mat").arg(i).toStdString().c_str());
142
        cvtools::writeMat(O, "O.mat");
143
        for(int m=0; m<M; m++)
144
            cvtools::writeMat(phim[m], QString("phim_%1.mat").arg(m).toStdString().c_str());
145
    #endif
146
 
147
    // Determine phase cue sequence
192 jakw 148
    std::vector<cv::Mat> Phim(M);
149
    Phim[0] = phim[0];
193 jakw 150
    for(int m=1; m<M; m++){
151
        cv::subtract(phim[m], phim[0], Phim[m]);
152
        Phim[m] = cvtools::modulo(Phim[m], 2.0*CV_PI);
153
    }
192 jakw 154
 
155
    // Note: Phim[1] is the cue of highest quality
156
 
193 jakw 157
    #if 0
158
        for(int m=0; m<M; m++)
159
            cvtools::writeMat(Phim[m], QString("Phim_%1.mat").arg(m).toStdString().c_str());
160
    #endif
192 jakw 161
 
193 jakw 162
    // Compute embedded frequencies
163
    float Fm[M];
164
    for(int m=0; m<M; m++){
165
        Fm[m] = 1.0;
166
        for(int i=0; i<=m; i++)
167
            Fm[m] *= 1.0/Tm[i];
168
    }
192 jakw 169
 
193 jakw 170
    // Unwrap phase cue sequence
171
    cv::Mat upCue = Phim[M-1];
172
    for(int m=M-2; m>0; m--){
173
        upCue = unwrapWithCue(Phim[m], upCue, screenCols*Fm[m]);
174
        #if 1
175
                cvtools::writeMat(upCue, "upCue.mat", "upCue");
176
        #endif
177
    }
192 jakw 178
 
193 jakw 179
    // Unwrap high frequency patterns
180
    std::vector<cv::Mat> upm(M);
181
    for(int m=0; m<M; m++){
182
        upm[m] = unwrapWithCue(phim[m], upCue, 1.0/Fm[1]);
183
    }
184
 
185
    #if 1
186
        for(int m=0; m<M; m++)
187
            cvtools::writeMat(upm[m], QString("upm_%1.mat").arg(m).toStdString().c_str());
188
    #endif
189
 
192 jakw 190
    // Determine range of phases (for outlier detection)
191
    cv::Mat upMin = upm[0];
192
    cv::Mat upMax = upm[0];
193
    for(int m=1; m<M; m++){
194
        upMin = cv::min(upMin, upm[m]);
195
        upMax = cv::max(upMax, upm[m]);
196
    }
197
    upRange = upMax-upMin;
198
 
199
    // Return average of phase maps
200
    up = upm[0];
201
    for(int m=1; m<M; m++)
202
        up += upm[m];
203
    up /= M;
204
}
205
 
206
void AlgorithmPhaseShiftEmbedded::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){
207
 
208
    assert(frames0.size() == N);
209
    assert(frames1.size() == N);
210
 
211
    int frameRows = frames0[0].rows;
212
    int frameCols = frames0[0].cols;
213
 
214
    // Rectifying homographies (rotation+projections)
215
    cv::Size frameSize(frameCols, frameRows);
216
    cv::Mat R, T;
217
    // stereoRectify segfaults unless R is double precision
218
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
219
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
220
    cv::Mat R0, R1, P0, P1, QRect;
221
    cv::stereoRectify(calibration.K0, calibration.k0, calibration.K1, calibration.k1, frameSize, R, T, R0, R1, P0, P1, QRect, 0);
222
 
223
    // Interpolation maps (lens distortion and rectification)
224
    cv::Mat map0X, map0Y, map1X, map1Y;
225
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0, R0, P0, frameSize, CV_32F, map0X, map0Y);
226
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1, R1, P1, frameSize, CV_32F, map1X, map1Y);
227
 
228
    int frameRectRows = map0X.rows;
229
    int frameRectCols = map0X.cols;
230
 
231
    // Gray-scale and remap
232
    std::vector<cv::Mat> frames0Rect(N);
233
    std::vector<cv::Mat> frames1Rect(N);
234
    for(unsigned int i=0; i<N; i++){
235
        cv::Mat temp;
236
        cv::cvtColor(frames0[i], temp, CV_BayerBG2GRAY);
237
        cv::remap(temp, frames0Rect[i], map0X, map0Y, CV_INTER_LINEAR);
238
        cv::cvtColor(frames1[i], temp, CV_BayerBG2GRAY);
239
        cv::remap(temp, frames1Rect[i], map1X, map1Y, CV_INTER_LINEAR);
240
    }
241
 
242
    // Decode camera 0
243
    std::vector<cv::Mat> frames0Patterns(frames0Rect.begin()+2, frames0Rect.end());
244
 
245
    cv::Mat up0, up0Range;
193 jakw 246
    decodeEmbeddedPS(frames0Patterns, up0, up0Range, screenCols);
192 jakw 247
    up0 *= screenCols;
248
 
249
    #ifdef QT_DEBUG
250
        cvtools::writeMat(up0, "up0.mat", "up0");
251
        cvtools::writeMat(up0Range, "up0Range.mat", "up0Range");
252
    #endif
253
 
254
    // Decode camera 1
255
    std::vector<cv::Mat> frames1Patterns(frames1Rect.begin()+2, frames1Rect.end());
256
 
257
    cv::Mat up1, up1Range;
193 jakw 258
    decodeEmbeddedPS(frames1Patterns, up1, up1Range, screenCols);
192 jakw 259
    up1 *= screenCols;
260
 
261
    #ifdef QT_DEBUG
262
        cvtools::writeMat(up1, "up1.mat", "up1");
263
    #endif
264
 
265
    // Color debayer and remap
266
    cv::Mat color0, color1;
267
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
268
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
269
 
270
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
271
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
272
 
273
    #ifdef QT_DEBUG
274
        cvtools::writeMat(color0, "color0.mat", "color0");
275
        cvtools::writeMat(color1, "color1.mat", "color1");
276
    #endif
277
 
278
    // Occlusion masks
279
    cv::Mat occlusion0, occlusion1;
280
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
281
    occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
282
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
283
    occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
284
 
285
//    // Threshold on energy at primary frequency
286
//    occlusion0 = occlusion0 & (amplitude0 > 5.0*nStepsPrimary);
287
//    occlusion1 = occlusion1 & (amplitude1 > 5.0*nStepsPrimary);
288
 
289
//    // Erode occlusion masks
290
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
291
//    cv::erode(occlusion0, occlusion0, strel);
292
//    cv::erode(occlusion1, occlusion1, strel);
293
 
294
    // Threshold on gradient of phase
295
    cv::Mat edges0;
296
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
297
    occlusion0 = occlusion0 & (abs(edges0) < 150);
298
 
299
    cv::Mat edges1;
300
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
301
    occlusion1 = occlusion1 & (abs(edges1) < 150);
302
 
303
    #ifdef QT_DEBUG
304
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
305
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
306
    #endif
307
 
308
    // Match phase maps
309
 
310
    // camera0 against camera1
311
    std::vector<cv::Vec2f> q0, q1;
312
    for(int row=0; row<frameRectRows; row++){
313
        for(int col=0; col<frameRectCols; col++){
314
 
315
            if(!occlusion0.at<char>(row,col))
316
                continue;
317
 
318
            float up0i = up0.at<float>(row,col);
319
            for(int col1=0; col1<up1.cols-1; col1++){
320
 
321
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
322
                    continue;
323
 
324
                float up1Left = up1.at<float>(row,col1);
325
                float up1Right = up1.at<float>(row,col1+1);
326
 
327
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
328
 
329
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
330
 
331
                    q0.push_back(cv::Point2f(col, row));
332
                    q1.push_back(cv::Point2f(col1i, row));
333
 
334
                    break;
335
                }
336
            }
337
        }
338
    }
339
 
340
 
341
    int nMatches = q0.size();
342
 
343
    if(nMatches < 1){
344
        Q.resize(0);
345
        color.resize(0);
346
 
347
        return;
348
    }
349
 
350
    // Retrieve color information
351
    color.resize(nMatches);
352
    for(int i=0; i<nMatches; i++){
353
 
354
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
355
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
356
 
357
        color[i] = 0.5*c0 + 0.5*c1;
358
    }
359
 
360
    // Triangulate points
361
    cv::Mat QMatHomogenous, QMat;
362
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
363
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
364
 
365
    // Undo rectification
366
    cv::Mat R0Inv;
367
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
368
    QMat = R0Inv*QMat;
369
 
370
    cvtools::matToPoints3f(QMat, Q);
371
 
372
}