Subversion Repositories seema-scanner

Rev

Rev 207 | Rev 228 | 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
208 flgw 147
    occlusion0 = occlusion0 & (amplitude0Primary > 5.0*nStepsPrimary);
207 flgw 148
    // Threshold on energy ratios
208 flgw 149
    occlusion0 = occlusion0 & (amplitude0Primary > 0.85*energy0Primary);
150
    occlusion0 = occlusion0 & (amplitude0Secondary > 0.85*energy0Secondary);
207 flgw 151
 
208 flgw 152
    #ifdef SM_DEBUG
185 jakw 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
208 flgw 221
    occlusion1 = occlusion1 & (amplitude1Primary > 5.0*nStepsPrimary);
182 jakw 222
    // Threshold on energy ratios
200 jakw 223
    occlusion1 = occlusion1 & (amplitude1Primary > 0.85*energy1Primary);
224
    occlusion1 = occlusion1 & (amplitude1Secondary > 0.85*energy1Secondary);
70 jakw 225
 
208 flgw 226
    #ifdef SM_DEBUG
207 flgw 227
        cvtools::writeMat(up1, "up1.mat", "up1");
228
    #endif
229
}
230
 
182 jakw 231
//    // Erode occlusion masks
232
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
233
//    cv::erode(occlusion0, occlusion0, strel);
234
//    cv::erode(occlusion1, occlusion1, strel);
207 flgw 235
{
190 jakw 236
    // Threshold on gradient of phase
237
    cv::Mat edges0;
238
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
195 jakw 239
    occlusion0 = occlusion0 & (abs(edges0) < 10);
71 jakw 240
 
190 jakw 241
    cv::Mat edges1;
242
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
195 jakw 243
    occlusion1 = occlusion1 & (abs(edges1) < 10);
71 jakw 244
 
208 flgw 245
    #ifdef SM_DEBUG
195 jakw 246
        cvtools::writeMat(edges0, "edges0.mat", "edges0");
247
        cvtools::writeMat(edges1, "edges1.mat", "edges1");
185 jakw 248
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
182 jakw 249
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
250
    #endif
207 flgw 251
}
70 jakw 252
    // Match phase maps
253
 
254
    // camera0 against camera1
178 jakw 255
    std::vector<cv::Vec2f> q0, q1;
70 jakw 256
    for(int row=0; row<frameRectRows; row++){
257
        for(int col=0; col<frameRectCols; col++){
258
 
178 jakw 259
            if(!occlusion0.at<char>(row,col))
70 jakw 260
                continue;
261
 
178 jakw 262
            float up0i = up0.at<float>(row,col);
263
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 264
 
178 jakw 265
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 266
                    continue;
267
 
178 jakw 268
                float up1Left = up1.at<float>(row,col1);
269
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 270
 
190 jakw 271
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
70 jakw 272
 
273
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
274
 
178 jakw 275
                    q0.push_back(cv::Point2f(col, row));
276
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 277
 
278
                    break;
70 jakw 279
                }
280
            }
281
        }
282
    }
283
 
284
 
178 jakw 285
    int nMatches = q0.size();
74 jakw 286
 
70 jakw 287
    if(nMatches < 1){
288
        Q.resize(0);
289
        color.resize(0);
290
 
291
        return;
292
    }
207 flgw 293
{
294
    // color debayer and remap
295
    cv::Mat color0, color1;
296
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
297
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
70 jakw 298
 
207 flgw 299
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
300
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
301
 
208 flgw 302
    #ifdef SM_DEBUG
207 flgw 303
        cvtools::writeMat(color0, "color0.mat", "color0");
304
        cvtools::writeMat(color1, "color1.mat", "color1");
305
    #endif
306
 
307
        // Retrieve color information
70 jakw 308
    color.resize(nMatches);
309
    for(int i=0; i<nMatches; i++){
310
 
178 jakw 311
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
312
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
70 jakw 313
 
314
        color[i] = 0.5*c0 + 0.5*c1;
315
    }
207 flgw 316
}
70 jakw 317
    // Triangulate points
318
    cv::Mat QMatHomogenous, QMat;
178 jakw 319
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
70 jakw 320
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
321
 
322
    // Undo rectification
323
    cv::Mat R0Inv;
324
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
325
    QMat = R0Inv*QMat;
326
 
327
    cvtools::matToPoints3f(QMat, Q);
328
 
4 jakw 329
}