Subversion Repositories seema-scanner

Rev

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

Rev Author Line No. Line
182 jakw 1
//
2
// Three Frequency Phase Shifting using the Heterodyne Principle
3
//
4
// This implementation follows "Reich, Ritter, Thesing, White light heterodyne principle for 3D-measurement", SPIE (1997)
5
//
188 jakw 6
// The number of periods in the First and Second frequencies can be chosen freely, but small changes can have a considerable impact on quality.
7
// The number of phase shifts can be chosen freely (min. 3), and higher values reduce the effects of image noise. They also allow us to filter bad points based on energy at non-First frequencies.
182 jakw 8
//
9
 
10
 
128 jakw 11
#include "AlgorithmPhaseShiftThreeFreq.h"
4 jakw 12
#include <math.h>
13
 
14
#include "cvtools.h"
182 jakw 15
#include "algorithmtools.h"
4 jakw 16
 
17
#ifndef M_PI
18
    #define M_PI 3.14159265358979323846
19
#endif
20
 
188 jakw 21
static unsigned int nStepsFirst = 8; // number of shifts/steps in First
22
static unsigned int nStepsSecond = 8; // number of shifts/steps in Second
23
static unsigned int nStepsThird = 8; // number of shifts/steps in Third
24
static float nPeriodsFirst = 24; // First period
25
static float nPeriodsSecond = 30; // First period
4 jakw 26
 
128 jakw 27
AlgorithmPhaseShiftThreeFreq::AlgorithmPhaseShiftThreeFreq(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
4 jakw 28
 
72 jakw 29
    // Set N
188 jakw 30
    N = 2+nStepsFirst+nStepsSecond+nStepsThird;
72 jakw 31
 
190 jakw 32
    // Determine the third number of periods to fulfill the heterodyne condition
188 jakw 33
    float nPeriodsThird = 1 + 2*nPeriodsSecond - nPeriodsFirst;
182 jakw 34
 
70 jakw 35
    // all on pattern
36
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
37
    patterns.push_back(allOn);
38
 
39
    // all off pattern
40
    cv::Mat allOff(1, screenCols, CV_8UC3, cv::Scalar::all(0));
41
    patterns.push_back(allOff);
42
 
4 jakw 43
    // Precompute encoded patterns
44
    const float pi = M_PI;
45
 
188 jakw 46
    // First encoding patterns
47
    for(unsigned int i=0; i<nStepsFirst; i++){
48
        float phase = 2.0*pi/nStepsFirst * i;
49
        float pitch = screenCols/nPeriodsFirst;
70 jakw 50
        cv::Mat patternI(1,1,CV_8U);
51
        patternI = computePhaseVector(screenCols, phase, pitch);
52
        patterns.push_back(patternI.t());
53
    }
4 jakw 54
 
188 jakw 55
    // Second encoding patterns
56
    for(unsigned int i=0; i<nStepsSecond; i++){
57
        float phase = 2.0*pi/nStepsSecond * i;
58
        float pitch = screenCols/nPeriodsSecond;
72 jakw 59
        cv::Mat patternI(1,1,CV_8U);
70 jakw 60
        patternI = computePhaseVector(screenCols, phase, pitch);
61
        patterns.push_back(patternI.t());
4 jakw 62
    }
188 jakw 63
    // Third encoding patterns
64
    for(unsigned int i=0; i<nStepsThird; i++){
65
        float phase = 2.0*pi/nStepsThird * i;
66
        float pitch = screenCols/nPeriodsThird;
128 jakw 67
        cv::Mat patternI(1,1,CV_8U);
68
        patternI = computePhaseVector(screenCols, phase, pitch);
69
        patterns.push_back(patternI.t());
70
    }
4 jakw 71
 
72
}
73
 
128 jakw 74
cv::Mat AlgorithmPhaseShiftThreeFreq::getEncodingPattern(unsigned int depth){
4 jakw 75
    return patterns[depth];
76
}
77
 
128 jakw 78
void AlgorithmPhaseShiftThreeFreq::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){
4 jakw 79
 
70 jakw 80
    const float pi = M_PI;
81
 
82
    assert(frames0.size() == N);
83
    assert(frames1.size() == N);
84
 
85
    int frameRows = frames0[0].rows;
86
    int frameCols = frames0[0].cols;
87
 
190 jakw 88
    float nPeriodsThird = 1 + 2*nPeriodsSecond - nPeriodsFirst;
89
 
90
 
179 jakw 91
    // Rectifying homographies (rotation+projections)
92
    cv::Size frameSize(frameCols, frameRows);
93
    cv::Mat R, T;
94
    // stereoRectify segfaults unless R is double precision
95
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
96
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
97
    cv::Mat R0, R1, P0, P1, QRect;
98
    cv::stereoRectify(calibration.K0, calibration.k0, calibration.K1, calibration.k1, frameSize, R, T, R0, R1, P0, P1, QRect, 0);
99
 
100
    // Interpolation maps (lens distortion and rectification)
101
    cv::Mat map0X, map0Y, map1X, map1Y;
102
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0, R0, P0, frameSize, CV_32F, map0X, map0Y);
103
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1, R1, P1, frameSize, CV_32F, map1X, map1Y);
104
 
105
 
106
    // Gray-scale and remap
107
    std::vector<cv::Mat> frames0Rect(N);
108
    std::vector<cv::Mat> frames1Rect(N);
167 jakw 109
    for(unsigned int i=0; i<N; i++){
179 jakw 110
        cv::Mat temp;
111
        cv::cvtColor(frames0[i], temp, CV_BayerBG2GRAY);
112
        cv::remap(temp, frames0Rect[i], map0X, map0Y, CV_INTER_LINEAR);
113
        cv::cvtColor(frames1[i], temp, CV_BayerBG2GRAY);
114
        cv::remap(temp, frames1Rect[i], map1X, map1Y, CV_INTER_LINEAR);
70 jakw 115
    }
116
 
117
    // Decode camera0
188 jakw 118
    std::vector<cv::Mat> frames0First(frames0Rect.begin()+2, frames0Rect.begin()+2+nStepsFirst);
119
    std::vector<cv::Mat> frames0Second(frames0Rect.begin()+2+nStepsFirst, frames0Rect.end()-nStepsThird);
120
    std::vector<cv::Mat> frames0Third(frames0Rect.end()-nStepsThird, frames0Rect.end());
129 jakw 121
 
188 jakw 122
    std::vector<cv::Mat> F0First = getDFTComponents(frames0First);
123
    cv::Mat up0First;
124
    cv::phase(F0First[2], -F0First[3], up0First);
125
    std::vector<cv::Mat> F0Second = getDFTComponents(frames0Second);
126
    cv::Mat up0Second;
127
    cv::phase(F0Second[2], -F0Second[3], up0Second);
128
    std::vector<cv::Mat> F0Third = getDFTComponents(frames0Third);
129
    cv::Mat up0Third;
130
    cv::phase(F0Third[2], -F0Third[3], up0Third);
128 jakw 131
 
190 jakw 132
    cv::Mat up0FS = up0Second - up0First;
133
    up0FS = cvtools::modulo(up0FS, 2.0*pi);
182 jakw 134
 
190 jakw 135
    cv::Mat up0ST = up0Third - up0Second;
136
    up0ST = cvtools::modulo(up0ST, 2.0*pi);
182 jakw 137
 
190 jakw 138
    cv::Mat up0FST = up0ST - up0FS;
139
    up0FST = cvtools::modulo(up0FST, 2.0*pi);
182 jakw 140
 
190 jakw 141
    cv::Mat up0F = unwrapWithCue(up0First, up0FST, nPeriodsFirst);
142
    cv::Mat up0S = unwrapWithCue(up0Second, up0FST, nPeriodsSecond);
143
    cv::Mat up0T = unwrapWithCue(up0Third, up0FST, nPeriodsThird);
144
    cv::Mat up0Mean = 1.0/3.0 * (up0F + up0S + up0T);
145
    cv::Mat up0Range = cv::max(up0F, cv::max(up0S, up0T)) - cv::min(up0F, cv::min(up0S, up0T));
146
    cv::Mat up0 = up0Mean * screenCols/(2.0*pi);
188 jakw 147
 
128 jakw 148
    cv::Mat amplitude0;
188 jakw 149
    cv::magnitude(F0First[2], -F0First[3], amplitude0);
70 jakw 150
 
151
    // Decode camera1
188 jakw 152
    std::vector<cv::Mat> frames1First(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsFirst);
153
    std::vector<cv::Mat> frames1Second(frames1Rect.begin()+2+nStepsFirst, frames1Rect.end()-nStepsThird);
154
    std::vector<cv::Mat> frames1Third(frames1Rect.end()-nStepsThird, frames1Rect.end());
129 jakw 155
 
188 jakw 156
    std::vector<cv::Mat> F1First = getDFTComponents(frames1First);
157
    cv::Mat up1First;
158
    cv::phase(F1First[2], -F1First[3], up1First);
159
    std::vector<cv::Mat> F1Second = getDFTComponents(frames1Second);
160
    cv::Mat up1Second;
161
    cv::phase(F1Second[2], -F1Second[3], up1Second);
162
    std::vector<cv::Mat> F1Third = getDFTComponents(frames1Third);
163
    cv::Mat up1Third;
164
    cv::phase(F1Third[2], -F1Third[3], up1Third);
128 jakw 165
 
190 jakw 166
    cv::Mat up1FS = up1Second - up1First;
167
    up1FS = cvtools::modulo(up1FS, 2.0*pi);
182 jakw 168
 
190 jakw 169
    cv::Mat up1ST = up1Third - up1Second;
170
    up1ST = cvtools::modulo(up1ST, 2.0*pi);
182 jakw 171
 
190 jakw 172
    cv::Mat up1FST = up1ST - up1FS;
173
    up1FST = cvtools::modulo(up1FST, 2.0*pi);
182 jakw 174
 
190 jakw 175
    cv::Mat up1F = unwrapWithCue(up1First, up1FST, nPeriodsFirst);
176
    cv::Mat up1S = unwrapWithCue(up1Second, up1FST, nPeriodsSecond);
177
    cv::Mat up1T = unwrapWithCue(up1Third, up1FST, nPeriodsThird);
178
    cv::Mat up1Mean = 1.0/3.0 * (up1F + up1S + up1T);
179
    cv::Mat up1Range = cv::max(up1F, cv::max(up1S, up1T)) - cv::min(up1F, cv::min(up1S, up1T));
180
    cv::Mat up1 = up1Mean * screenCols/(2.0*pi);
181
 
128 jakw 182
    cv::Mat amplitude1;
188 jakw 183
    cv::magnitude(F1First[2], -F1First[3], amplitude1);
70 jakw 184
 
185 jakw 185
    #ifdef QT_DEBUG
188 jakw 186
        cvtools::writeMat(up0First, "up0First.mat", "up0First");
187
        cvtools::writeMat(up0Second, "up0Second.mat", "up0Second");
188
        cvtools::writeMat(up0Third, "up0Third.mat", "up0Third");
190 jakw 189
        cvtools::writeMat(up0FS, "up0FS.mat", "up0FS");
190
        cvtools::writeMat(up0ST, "up0ST.mat", "up0ST");
191
        cvtools::writeMat(up0FST, "up0FST.mat", "up0FST");
192
        cvtools::writeMat(up0Mean, "up0Mean.mat", "up0Mean");
193
        cvtools::writeMat(up0Range, "up0Range.mat", "up0Range");
182 jakw 194
        cvtools::writeMat(up0, "up0.mat", "up0");
195
        cvtools::writeMat(up1, "up1.mat", "up1");
196
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
71 jakw 197
 
182 jakw 198
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
199
        cvtools::writeMat(amplitude1, "amplitude1.mat", "amplitude1");
200
    #endif
70 jakw 201
 
187 jakw 202
    // color debayer and remap
179 jakw 203
    cv::Mat color0, color1;
204
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
187 jakw 205
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
206
 
179 jakw 207
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
187 jakw 208
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
70 jakw 209
 
185 jakw 210
    #ifdef QT_DEBUG
182 jakw 211
        cvtools::writeMat(color0, "color0.mat", "color0");
212
        cvtools::writeMat(color1, "color1.mat", "color1");
213
    #endif
70 jakw 214
 
215
    // Occlusion masks
179 jakw 216
    cv::Mat occlusion0, occlusion1;
217
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
190 jakw 218
    occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
179 jakw 219
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
190 jakw 220
    occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
70 jakw 221
 
190 jakw 222
    // Threshold on range
223
    occlusion0 = occlusion0 & (up0Range < 0.05);
224
    occlusion1 = occlusion1 & (up1Range < 0.05);
225
 
226
//    // Erode occlusion masks
227
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
228
//    cv::erode(occlusion0, occlusion0, strel);
229
//    cv::erode(occlusion1, occlusion1, strel);
230
 
71 jakw 231
    // Threshold on gradient of phase
232
    cv::Mat edges0;
179 jakw 233
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
234
    occlusion0 = occlusion0 & (abs(edges0) < 150);
71 jakw 235
    cv::Mat edges1;
179 jakw 236
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
237
    occlusion1 = occlusion1 & (abs(edges1) < 150);
71 jakw 238
 
185 jakw 239
    #ifdef QT_DEBUG
182 jakw 240
        cvtools::writeMat(edges0, "edges0.mat", "edges0");
241
        cvtools::writeMat(edges1, "edges1.mat", "edges1");
242
    #endif
71 jakw 243
 
187 jakw 244
    #ifdef QT_DEBUG
245
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
246
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
247
    #endif
248
 
70 jakw 249
    // Match phase maps
250
    int frameRectRows = map0X.rows;
251
    int frameRectCols = map0X.cols;
252
 
253
    // camera0 against camera1
179 jakw 254
    std::vector<cv::Vec2f> q0, q1;
70 jakw 255
    for(int row=0; row<frameRectRows; row++){
256
        for(int col=0; col<frameRectCols; col++){
257
 
179 jakw 258
            if(!occlusion0.at<char>(row,col))
70 jakw 259
                continue;
260
 
179 jakw 261
            float up0i = up0.at<float>(row,col);
262
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 263
 
179 jakw 264
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 265
                    continue;
266
 
179 jakw 267
                float up1Left = up1.at<float>(row,col1);
268
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 269
 
189 jakw 270
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
70 jakw 271
 
272
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
273
 
179 jakw 274
                    q0.push_back(cv::Point2f(col, row));
275
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 276
 
277
                    break;
70 jakw 278
                }
279
            }
280
        }
281
    }
282
 
179 jakw 283
    int nMatches = q0.size();
70 jakw 284
 
285
    if(nMatches < 1){
286
        Q.resize(0);
287
        color.resize(0);
288
 
289
        return;
290
    }
291
 
292
    // Retrieve color information
293
    color.resize(nMatches);
294
    for(int i=0; i<nMatches; i++){
295
 
179 jakw 296
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
297
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
70 jakw 298
 
299
        color[i] = 0.5*c0 + 0.5*c1;
300
    }
301
 
302
    // Triangulate points
303
    cv::Mat QMatHomogenous, QMat;
179 jakw 304
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
70 jakw 305
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
306
 
307
    // Undo rectification
308
    cv::Mat R0Inv;
309
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
310
    QMat = R0Inv*QMat;
311
 
312
    cvtools::matToPoints3f(QMat, Q);
313
 
4 jakw 314
}