Subversion Repositories seema-scanner

Rev

Rev 193 | Go to most recent revision | Details | 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
15
static const int M = 3;
16
 
17
// Embedded frequencies
18
static const float Fm[M] = {1.0/16, 1.0/128, 1.0/1024};
19
 
20
// Number of patterns at each frequency
21
static const int Nm[M] = {3, 3, 2};
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
 
42
    // Encoding patterns
43
    for(int m=0; m<M; m++){
44
        int nSteps = Nm[m];
45
        float frequency = Fm[m];
46
        for(unsigned int i=0; i<nSteps; i++){
47
            float phase = 2.0*pi/nSteps * i;
48
            float pitch = 1.0/frequency;
49
            cv::Mat patternI(1,1,CV_8U);
50
            patternI = computePhaseVector(screenCols, phase, pitch);
51
            patterns.push_back(patternI.t());
52
        }
53
    }
54
 
55
}
56
 
57
cv::Mat AlgorithmPhaseShiftEmbedded::getEncodingPattern(unsigned int depth){
58
    return patterns[depth];
59
}
60
 
61
static void decodeEmbeddedPS(const std::vector<cv::Mat> &frames, cv::Mat &up, cv::Mat &upRange){
62
 
63
    const int N = frames.size();
64
 
65
    // Construct shift matrix
66
    cv::Mat A(N, 1 + 2*N, CV_32F);
67
 
68
    int rowBegin = 0;
69
    for(int m=0; m<M; m++){
70
 
71
        int nSteps = Nm[m];
72
 
73
        cv::Mat Am(nSteps, 2, CV_32F);
74
 
75
        for(unsigned int i=0; i<nSteps; i++){
76
            float phase = 2.0*CV_PI/nSteps * i;
77
 
78
            Am.at<float>(i, 0) = std::cos(phase);
79
            Am.at<float>(i, 1) = -std::sin(phase);
80
        }
81
 
82
        // Copy into the A matrix
83
        Am.copyTo(A.rowRange(rowBegin, rowBegin+nSteps).colRange(1+2*m, 1+2*(m+1)));
84
        rowBegin += nSteps;
85
    }
86
 
87
    int frameRows = frames[0].rows;
88
    int frameCols = frames[0].cols;
89
 
90
    // DC-offset
91
    cv::Mat O(frameRows, frameCols, CV_32F);
92
 
93
    // Relative phase maps
94
    std::vector<cv::Mat> phim;
95
    for(int i=0; i<N; i++)
96
        phim.push_back(cv::Mat(frameRows, frameCols, CV_32F));
97
 
98
    // Solve for relative phase values
99
    for(int row=0; row<frameRows; row++){
100
        for(int col=0; col<frameCols; col++){
101
 
102
            // Measurement vector
103
            cv::Mat r(N, 1, CV_32F);
104
            for(int i=0; i<N; i++)
105
                r.at<float>(i) = frames[i].at<float>(row, col);
106
 
107
            // Solve
108
            cv::Mat u; //[o, a cos1, a sin1, a cos2, a sin2, ...]
109
            cv::solve(A, r, u);
110
 
111
            for(int m=0; m<M; m++)
112
                phim[m].at<float>(row, col) = std::atan2(u.at<float>(m*2+1), u.at<float>(m*2+2));
113
 
114
            O.at<float>(row, col) = u.at<float>(0);
115
        }
116
 
117
    }
118
 
119
    // Determine phase cues
120
    std::vector<cv::Mat> Phim(M);
121
    Phim[0] = phim[0];
122
 
123
    for(int i=1; i<M; i++)
124
        cv::subtract(phim[i], phim[0], Phim[i]);
125
 
126
    // Note: Phim[1] is the cue of highest quality
127
 
128
    std::vector<cv::Mat> upm;
129
 
130
    for(int m=0; m<M; m++)
131
        upm[m] = unwrapWithCue(phim[m], Phim[1], 1.0/Fm[1]);
132
 
133
 
134
    // Determine range of phases (for outlier detection)
135
    cv::Mat upMin = upm[0];
136
    cv::Mat upMax = upm[0];
137
    for(int m=1; m<M; m++){
138
        upMin = cv::min(upMin, upm[m]);
139
        upMax = cv::max(upMax, upm[m]);
140
    }
141
    upRange = upMax-upMin;
142
 
143
    // Return average of phase maps
144
    up = upm[0];
145
    for(int m=1; m<M; m++)
146
        up += upm[m];
147
    up /= M;
148
}
149
 
150
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){
151
 
152
    assert(frames0.size() == N);
153
    assert(frames1.size() == N);
154
 
155
    int frameRows = frames0[0].rows;
156
    int frameCols = frames0[0].cols;
157
 
158
    // Rectifying homographies (rotation+projections)
159
    cv::Size frameSize(frameCols, frameRows);
160
    cv::Mat R, T;
161
    // stereoRectify segfaults unless R is double precision
162
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
163
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
164
    cv::Mat R0, R1, P0, P1, QRect;
165
    cv::stereoRectify(calibration.K0, calibration.k0, calibration.K1, calibration.k1, frameSize, R, T, R0, R1, P0, P1, QRect, 0);
166
 
167
    // Interpolation maps (lens distortion and rectification)
168
    cv::Mat map0X, map0Y, map1X, map1Y;
169
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0, R0, P0, frameSize, CV_32F, map0X, map0Y);
170
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1, R1, P1, frameSize, CV_32F, map1X, map1Y);
171
 
172
    int frameRectRows = map0X.rows;
173
    int frameRectCols = map0X.cols;
174
 
175
    // Gray-scale and remap
176
    std::vector<cv::Mat> frames0Rect(N);
177
    std::vector<cv::Mat> frames1Rect(N);
178
    for(unsigned int i=0; i<N; i++){
179
        cv::Mat temp;
180
        cv::cvtColor(frames0[i], temp, CV_BayerBG2GRAY);
181
        cv::remap(temp, frames0Rect[i], map0X, map0Y, CV_INTER_LINEAR);
182
        cv::cvtColor(frames1[i], temp, CV_BayerBG2GRAY);
183
        cv::remap(temp, frames1Rect[i], map1X, map1Y, CV_INTER_LINEAR);
184
    }
185
 
186
    // Decode camera 0
187
    std::vector<cv::Mat> frames0Patterns(frames0Rect.begin()+2, frames0Rect.end());
188
 
189
    cv::Mat up0, up0Range;
190
    decodeEmbeddedPS(frames0Patterns, up0, up0Range);
191
    up0 *= screenCols;
192
 
193
    #ifdef QT_DEBUG
194
        cvtools::writeMat(up0, "up0.mat", "up0");
195
        cvtools::writeMat(up0Range, "up0Range.mat", "up0Range");
196
    #endif
197
 
198
    // Decode camera 1
199
    std::vector<cv::Mat> frames1Patterns(frames1Rect.begin()+2, frames1Rect.end());
200
 
201
    cv::Mat up1, up1Range;
202
    decodeEmbeddedPS(frames1Patterns, up1, up1Range);
203
    up1 *= screenCols;
204
 
205
    #ifdef QT_DEBUG
206
        cvtools::writeMat(up1, "up1.mat", "up1");
207
    #endif
208
 
209
    // Color debayer and remap
210
    cv::Mat color0, color1;
211
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
212
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
213
 
214
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
215
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
216
 
217
    #ifdef QT_DEBUG
218
        cvtools::writeMat(color0, "color0.mat", "color0");
219
        cvtools::writeMat(color1, "color1.mat", "color1");
220
    #endif
221
 
222
    // Occlusion masks
223
    cv::Mat occlusion0, occlusion1;
224
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
225
    occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
226
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
227
    occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
228
 
229
//    // Threshold on energy at primary frequency
230
//    occlusion0 = occlusion0 & (amplitude0 > 5.0*nStepsPrimary);
231
//    occlusion1 = occlusion1 & (amplitude1 > 5.0*nStepsPrimary);
232
 
233
//    // Erode occlusion masks
234
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
235
//    cv::erode(occlusion0, occlusion0, strel);
236
//    cv::erode(occlusion1, occlusion1, strel);
237
 
238
    // Threshold on gradient of phase
239
    cv::Mat edges0;
240
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
241
    occlusion0 = occlusion0 & (abs(edges0) < 150);
242
 
243
    cv::Mat edges1;
244
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
245
    occlusion1 = occlusion1 & (abs(edges1) < 150);
246
 
247
    #ifdef QT_DEBUG
248
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
249
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
250
    #endif
251
 
252
    // Match phase maps
253
 
254
    // camera0 against camera1
255
    std::vector<cv::Vec2f> q0, q1;
256
    for(int row=0; row<frameRectRows; row++){
257
        for(int col=0; col<frameRectCols; col++){
258
 
259
            if(!occlusion0.at<char>(row,col))
260
                continue;
261
 
262
            float up0i = up0.at<float>(row,col);
263
            for(int col1=0; col1<up1.cols-1; col1++){
264
 
265
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
266
                    continue;
267
 
268
                float up1Left = up1.at<float>(row,col1);
269
                float up1Right = up1.at<float>(row,col1+1);
270
 
271
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
272
 
273
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
274
 
275
                    q0.push_back(cv::Point2f(col, row));
276
                    q1.push_back(cv::Point2f(col1i, row));
277
 
278
                    break;
279
                }
280
            }
281
        }
282
    }
283
 
284
 
285
    int nMatches = q0.size();
286
 
287
    if(nMatches < 1){
288
        Q.resize(0);
289
        color.resize(0);
290
 
291
        return;
292
    }
293
 
294
    // Retrieve color information
295
    color.resize(nMatches);
296
    for(int i=0; i<nMatches; i++){
297
 
298
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
299
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
300
 
301
        color[i] = 0.5*c0 + 0.5*c1;
302
    }
303
 
304
    // Triangulate points
305
    cv::Mat QMatHomogenous, QMat;
306
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
307
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
308
 
309
    // Undo rectification
310
    cv::Mat R0Inv;
311
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
312
    QMat = R0Inv*QMat;
313
 
314
    cvtools::matToPoints3f(QMat, Q);
315
 
316
}