Subversion Repositories seema-scanner

Rev

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

Rev Author Line No. Line
181 jakw 1
//
2
// Two 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
// Different from the paper, it uses only two different frequencies.
6
//
182 jakw 7
// The number of periods in the primary frequency can be chosen freely, but small changes can have a considerable impact on quality.
181 jakw 8
// 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-primary frequencies.
9
//
10
 
128 jakw 11
#include "AlgorithmPhaseShiftTwoFreq.h"
4 jakw 12
#include <math.h>
13
 
14
#include "cvtools.h"
182 jakw 15
#include "algorithmtools.h"
4 jakw 16
 
143 jakw 17
static unsigned int nStepsPrimary = 16; // number of shifts/steps in primary
18
static unsigned int nStepsSecondary = 8; // number of shifts/steps in secondary
190 jakw 19
static float nPeriodsPrimary = 40; // primary period
4 jakw 20
 
128 jakw 21
AlgorithmPhaseShiftTwoFreq::AlgorithmPhaseShiftTwoFreq(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
4 jakw 22
 
72 jakw 23
    // Set N
118 jakw 24
    N = 2+nStepsPrimary+nStepsSecondary;
72 jakw 25
 
190 jakw 26
    // Determine the secondary (wider) period to fulfill the heterodyne condition
27
    float nPeriodsSecondary = nPeriodsPrimary + 1;
74 jakw 28
 
70 jakw 29
    // all on pattern
30
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
31
    patterns.push_back(allOn);
32
 
33
    // all off pattern
34
    cv::Mat allOff(1, screenCols, CV_8UC3, cv::Scalar::all(0));
35
    patterns.push_back(allOff);
36
 
74 jakw 37
    // Primary encoding patterns
118 jakw 38
    for(unsigned int i=0; i<nStepsPrimary; i++){
192 jakw 39
        float phase = 2.0*CV_PI/nStepsPrimary * i;
190 jakw 40
        float pitch = screenCols/nPeriodsPrimary;
70 jakw 41
        cv::Mat patternI(1,1,CV_8U);
42
        patternI = computePhaseVector(screenCols, phase, pitch);
43
        patterns.push_back(patternI.t());
44
    }
4 jakw 45
 
74 jakw 46
    // Secondary encoding patterns
118 jakw 47
    for(unsigned int i=0; i<nStepsSecondary; i++){
192 jakw 48
        float phase = 2.0*CV_PI/nStepsSecondary * i;
190 jakw 49
        float pitch = screenCols/nPeriodsSecondary;
72 jakw 50
        cv::Mat patternI(1,1,CV_8U);
70 jakw 51
        patternI = computePhaseVector(screenCols, phase, pitch);
52
        patterns.push_back(patternI.t());
4 jakw 53
    }
54
 
72 jakw 55
 
4 jakw 56
}
57
 
128 jakw 58
cv::Mat AlgorithmPhaseShiftTwoFreq::getEncodingPattern(unsigned int depth){
4 jakw 59
    return patterns[depth];
60
}
61
 
207 flgw 62
void AlgorithmPhaseShiftTwoFreq::get3DPoints(const 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 63
 
70 jakw 64
    assert(frames0.size() == N);
65
    assert(frames1.size() == N);
66
 
207 flgw 67
    cv::Mat map0X, map0Y, map1X, map1Y;
68
    cv::Mat R0, P0, P1;
69
{
70 jakw 70
    int frameRows = frames0[0].rows;
71
    int frameCols = frames0[0].cols;
72
 
178 jakw 73
    // Rectifying homographies (rotation+projections)
74
    cv::Size frameSize(frameCols, frameRows);
75
    cv::Mat R, T;
76
    // stereoRectify segfaults unless R is double precision
77
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
78
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
207 flgw 79
    cv::Mat  R1, QRect;
178 jakw 80
    cv::stereoRectify(calibration.K0, calibration.k0, calibration.K1, calibration.k1, frameSize, R, T, R0, R1, P0, P1, QRect, 0);
81
 
82
    // Interpolation maps (lens distortion and rectification)
83
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0, R0, P0, frameSize, CV_32F, map0X, map0Y);
84
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1, R1, P1, frameSize, CV_32F, map1X, map1Y);
85
 
207 flgw 86
    }
87
 
182 jakw 88
    int frameRectRows = map0X.rows;
89
    int frameRectCols = map0X.cols;
90
 
207 flgw 91
    cv::Mat up0;
92
    cv::Mat occlusion0;
93
{
94
        // Gray-scale and remap
95
        std::vector<cv::Mat> frames0Rect(N);
96
        for(unsigned int i=0; i<N; i++){
97
            cv::Mat temp;
98
            cv::cvtColor(frames0[i], temp, CV_BayerBG2GRAY);
99
            cv::remap(temp, frames0Rect[i], map0X, map0Y, CV_INTER_LINEAR);
100
        }
101
        // Occlusion masks
102
        cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
103
        occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
70 jakw 104
 
207 flgw 105
        // Decode camera0
106
        std::vector<cv::Mat> frames0Primary(frames0Rect.begin()+2, frames0Rect.begin()+2+nStepsPrimary);
107
        std::vector<cv::Mat> frames0Secondary(frames0Rect.begin()+2+nStepsPrimary, frames0Rect.end());
182 jakw 108
 
207 flgw 109
        frames0Rect.clear();
110
 
76 jakw 111
    std::vector<cv::Mat> F0Primary = getDFTComponents(frames0Primary);
207 flgw 112
    frames0Primary.clear();
74 jakw 113
    cv::Mat up0Primary;
76 jakw 114
    cv::phase(F0Primary[2], -F0Primary[3], up0Primary);
182 jakw 115
 
76 jakw 116
    std::vector<cv::Mat> F0Secondary = getDFTComponents(frames0Secondary);
207 flgw 117
    frames0Secondary.clear();
76 jakw 118
    cv::Mat up0Secondary;
119
    cv::phase(F0Secondary[2], -F0Secondary[3], up0Secondary);
182 jakw 120
 
190 jakw 121
    cv::Mat up0Equivalent = up0Secondary - up0Primary;
192 jakw 122
    up0Equivalent = cvtools::modulo(up0Equivalent, 2.0*CV_PI);
207 flgw 123
    up0 = unwrapWithCue(up0Primary, up0Equivalent, nPeriodsPrimary);
192 jakw 124
    up0 *= screenCols/(2.0*CV_PI);
70 jakw 125
 
200 jakw 126
    // Signal energy at unit frequency
127
    cv::Mat amplitude0Primary, amplitude0Secondary;
128
    cv::magnitude(F0Primary[2], -F0Primary[3], amplitude0Primary);
129
    cv::magnitude(F0Secondary[2], -F0Secondary[3], amplitude0Secondary);
130
 
182 jakw 131
    // Collected signal energy at higher frequencies
132
    cv::Mat energy0Primary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
133
    for(unsigned int i=0; i<nStepsPrimary-1; i++){
134
        cv::Mat magnitude;
135
        cv::magnitude(F0Primary[i*2 + 2], F0Primary[i*2 + 3], magnitude);
136
        cv::add(energy0Primary, magnitude, energy0Primary, cv::noArray(), CV_32F);
137
    }
138
 
139
    cv::Mat energy0Secondary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
140
    for(unsigned int i=0; i<nStepsSecondary-1; i++){
141
        cv::Mat magnitude;
142
        cv::magnitude(F0Secondary[i*2 + 2], F0Secondary[i*2 + 3], magnitude);
143
        cv::add(energy0Secondary, magnitude, energy0Secondary, cv::noArray(), CV_32F);
144
    }
145
 
207 flgw 146
    // Threshold on energy at primary frequency
147
    occlusion0 = occlusion0 & (amplitude0 > 5.0*nStepsPrimary);
148
    // Threshold on energy ratios
149
    occlusion0 = occlusion0 & (amplitude0 > 0.85*energy0Primary);
150
    occlusion0 = occlusion0 & (amplitude0 > 0.85*energy0Secondary);
151
 
185 jakw 152
    #ifdef QT_DEBUG
153
        cvtools::writeMat(up0Primary, "up0Primary.mat", "up0Primary");
154
        cvtools::writeMat(up0Secondary, "up0Secondary.mat", "up0Secondary");
155
        cvtools::writeMat(up0Equivalent, "up0Equivalent.mat", "up0Equivalent");
156
        cvtools::writeMat(up0, "up0.mat", "up0");
200 jakw 157
        cvtools::writeMat(amplitude0Primary, "amplitude0Primary.mat", "amplitude0Primary");
185 jakw 158
        cvtools::writeMat(energy0Primary, "energy0Primary.mat", "energy0Primary");
159
        cvtools::writeMat(energy0Secondary, "energy0Secondary.mat", "energy0Secondary");
160
    #endif
207 flgw 161
}
185 jakw 162
 
207 flgw 163
    cv::Mat up1;
164
    cv::Mat occlusion1;
165
    {
182 jakw 166
 
207 flgw 167
        // Gray-scale and remap
168
        std::vector<cv::Mat> frames1Rect(N);
169
        for(unsigned int i=0; i<N; i++){
170
            cv::Mat temp;
171
            cv::cvtColor(frames1[i], temp, CV_BayerBG2GRAY);
172
            cv::remap(temp, frames1Rect[i], map1X, map1Y, CV_INTER_LINEAR);
173
        }
174
 
175
        // Occlusion masks
176
        cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
177
        occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
178
 
179
        // Decode camera1
180
        std::vector<cv::Mat> frames1Primary(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsPrimary);
181
        std::vector<cv::Mat> frames1Secondary(frames1Rect.begin()+2+nStepsPrimary, frames1Rect.end());
182
 
183
        frames1Rect.clear();
184
 
76 jakw 185
    std::vector<cv::Mat> F1Primary = getDFTComponents(frames1Primary);
207 flgw 186
    frames1Primary.clear();
74 jakw 187
    cv::Mat up1Primary;
76 jakw 188
    cv::phase(F1Primary[2], -F1Primary[3], up1Primary);
182 jakw 189
 
76 jakw 190
    std::vector<cv::Mat> F1Secondary = getDFTComponents(frames1Secondary);
207 flgw 191
    frames1Secondary.clear();
76 jakw 192
    cv::Mat up1Secondary;
193
    cv::phase(F1Secondary[2], -F1Secondary[3], up1Secondary);
182 jakw 194
 
190 jakw 195
    cv::Mat up1Equivalent = up1Secondary - up1Primary;
192 jakw 196
    up1Equivalent = cvtools::modulo(up1Equivalent, 2.0*CV_PI);
207 flgw 197
    up1 = unwrapWithCue(up1Primary, up1Equivalent, nPeriodsPrimary);
192 jakw 198
    up1 *= screenCols/(2.0*CV_PI);
70 jakw 199
 
200 jakw 200
    // Signal energy at unit frequency
201
    cv::Mat amplitude1Primary, amplitude1Secondary;
202
    cv::magnitude(F1Primary[2], -F1Primary[3], amplitude1Primary);
203
    cv::magnitude(F1Secondary[2], -F1Secondary[3], amplitude1Secondary);
204
 
182 jakw 205
    // Collected signal energy at higher frequencies
206
    cv::Mat energy1Primary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
207
    for(unsigned int i=0; i<nStepsPrimary-1; i++){
208
        cv::Mat magnitude;
209
        cv::magnitude(F1Primary[i*2 + 2], F1Primary[i*2 + 3], magnitude);
210
        cv::add(energy1Primary, magnitude, energy1Primary, cv::noArray(), CV_32F);
211
    }
212
 
213
    cv::Mat energy1Secondary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
214
    for(unsigned int i=0; i<nStepsSecondary-1; i++){
215
        cv::Mat magnitude;
216
        cv::magnitude(F1Secondary[i*2 + 2], F1Secondary[i*2 + 3], magnitude);
217
        cv::add(energy1Secondary, magnitude, energy1Secondary, cv::noArray(), CV_32F);
218
    }
219
 
128 jakw 220
    // Threshold on energy at primary frequency
207 flgw 221
    occlusion1 = occlusion1 & (amplitude1 > 5.0*nStepsPrimary);
182 jakw 222
    // Threshold on energy ratios
207 flgw 223
    occlusion1 = occlusion1 & (amplitude1 > 0.85*energy1Primary);
200 jakw 224
    occlusion1 = occlusion1 & (amplitude1Primary > 0.85*energy1Primary);
225
    occlusion1 = occlusion1 & (amplitude1Secondary > 0.85*energy1Secondary);
70 jakw 226
 
207 flgw 227
    #ifdef QT_DEBUG
228
        cvtools::writeMat(up1, "up1.mat", "up1");
229
    #endif
230
}
231
 
182 jakw 232
//    // Erode occlusion masks
233
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
234
//    cv::erode(occlusion0, occlusion0, strel);
235
//    cv::erode(occlusion1, occlusion1, strel);
207 flgw 236
{
190 jakw 237
    // Threshold on gradient of phase
238
    cv::Mat edges0;
239
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
195 jakw 240
    occlusion0 = occlusion0 & (abs(edges0) < 10);
71 jakw 241
 
190 jakw 242
    cv::Mat edges1;
243
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
195 jakw 244
    occlusion1 = occlusion1 & (abs(edges1) < 10);
71 jakw 245
 
185 jakw 246
    #ifdef QT_DEBUG
195 jakw 247
        cvtools::writeMat(edges0, "edges0.mat", "edges0");
248
        cvtools::writeMat(edges1, "edges1.mat", "edges1");
185 jakw 249
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
182 jakw 250
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
251
    #endif
207 flgw 252
}
70 jakw 253
    // Match phase maps
254
 
255
    // camera0 against camera1
178 jakw 256
    std::vector<cv::Vec2f> q0, q1;
70 jakw 257
    for(int row=0; row<frameRectRows; row++){
258
        for(int col=0; col<frameRectCols; col++){
259
 
178 jakw 260
            if(!occlusion0.at<char>(row,col))
70 jakw 261
                continue;
262
 
178 jakw 263
            float up0i = up0.at<float>(row,col);
264
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 265
 
178 jakw 266
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 267
                    continue;
268
 
178 jakw 269
                float up1Left = up1.at<float>(row,col1);
270
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 271
 
190 jakw 272
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
70 jakw 273
 
274
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
275
 
178 jakw 276
                    q0.push_back(cv::Point2f(col, row));
277
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 278
 
279
                    break;
70 jakw 280
                }
281
            }
282
        }
283
    }
284
 
285
 
178 jakw 286
    int nMatches = q0.size();
74 jakw 287
 
70 jakw 288
    if(nMatches < 1){
289
        Q.resize(0);
290
        color.resize(0);
291
 
292
        return;
293
    }
207 flgw 294
{
295
    // color debayer and remap
296
    cv::Mat color0, color1;
297
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
298
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
70 jakw 299
 
207 flgw 300
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
301
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
302
 
303
    #ifdef QT_DEBUG
304
        cvtools::writeMat(color0, "color0.mat", "color0");
305
        cvtools::writeMat(color1, "color1.mat", "color1");
306
    #endif
307
 
308
        // Retrieve color information
70 jakw 309
    color.resize(nMatches);
310
    for(int i=0; i<nMatches; i++){
311
 
178 jakw 312
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
313
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
70 jakw 314
 
315
        color[i] = 0.5*c0 + 0.5*c1;
316
    }
207 flgw 317
}
70 jakw 318
    // Triangulate points
319
    cv::Mat QMatHomogenous, QMat;
178 jakw 320
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
70 jakw 321
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
322
 
323
    // Undo rectification
324
    cv::Mat R0Inv;
325
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
326
    QMat = R0Inv*QMat;
327
 
328
    cvtools::matToPoints3f(QMat, Q);
329
 
4 jakw 330
}