Subversion Repositories seema-scanner

Rev

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