Subversion Repositories seema-scanner

Rev

Rev 195 | Rev 207 | 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
 
128 jakw 62
void AlgorithmPhaseShiftTwoFreq::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 63
 
70 jakw 64
    assert(frames0.size() == N);
65
    assert(frames1.size() == N);
66
 
67
    int frameRows = frames0[0].rows;
68
    int frameCols = frames0[0].cols;
69
 
178 jakw 70
    // Rectifying homographies (rotation+projections)
71
    cv::Size frameSize(frameCols, frameRows);
72
    cv::Mat R, T;
73
    // stereoRectify segfaults unless R is double precision
74
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
75
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
76
    cv::Mat R0, R1, P0, P1, QRect;
77
    cv::stereoRectify(calibration.K0, calibration.k0, calibration.K1, calibration.k1, frameSize, R, T, R0, R1, P0, P1, QRect, 0);
78
 
79
    // Interpolation maps (lens distortion and rectification)
80
    cv::Mat map0X, map0Y, map1X, map1Y;
81
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0, R0, P0, frameSize, CV_32F, map0X, map0Y);
82
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1, R1, P1, frameSize, CV_32F, map1X, map1Y);
83
 
182 jakw 84
    int frameRectRows = map0X.rows;
85
    int frameRectCols = map0X.cols;
86
 
179 jakw 87
    // Gray-scale and remap
178 jakw 88
    std::vector<cv::Mat> frames0Rect(N);
89
    std::vector<cv::Mat> frames1Rect(N);
167 jakw 90
    for(unsigned int i=0; i<N; i++){
178 jakw 91
        cv::Mat temp;
92
        cv::cvtColor(frames0[i], temp, CV_BayerBG2GRAY);
93
        cv::remap(temp, frames0Rect[i], map0X, map0Y, CV_INTER_LINEAR);
94
        cv::cvtColor(frames1[i], temp, CV_BayerBG2GRAY);
95
        cv::remap(temp, frames1Rect[i], map1X, map1Y, CV_INTER_LINEAR);
70 jakw 96
    }
97
 
98
    // Decode camera0
178 jakw 99
    std::vector<cv::Mat> frames0Primary(frames0Rect.begin()+2, frames0Rect.begin()+2+nStepsPrimary);
100
    std::vector<cv::Mat> frames0Secondary(frames0Rect.begin()+2+nStepsPrimary, frames0Rect.end());
182 jakw 101
 
76 jakw 102
    std::vector<cv::Mat> F0Primary = getDFTComponents(frames0Primary);
74 jakw 103
    cv::Mat up0Primary;
76 jakw 104
    cv::phase(F0Primary[2], -F0Primary[3], up0Primary);
182 jakw 105
 
76 jakw 106
    std::vector<cv::Mat> F0Secondary = getDFTComponents(frames0Secondary);
107
    cv::Mat up0Secondary;
108
    cv::phase(F0Secondary[2], -F0Secondary[3], up0Secondary);
182 jakw 109
 
190 jakw 110
    cv::Mat up0Equivalent = up0Secondary - up0Primary;
192 jakw 111
    up0Equivalent = cvtools::modulo(up0Equivalent, 2.0*CV_PI);
190 jakw 112
    cv::Mat up0 = unwrapWithCue(up0Primary, up0Equivalent, nPeriodsPrimary);
192 jakw 113
    up0 *= screenCols/(2.0*CV_PI);
70 jakw 114
 
200 jakw 115
    // Signal energy at unit frequency
116
    cv::Mat amplitude0Primary, amplitude0Secondary;
117
    cv::magnitude(F0Primary[2], -F0Primary[3], amplitude0Primary);
118
    cv::magnitude(F0Secondary[2], -F0Secondary[3], amplitude0Secondary);
119
 
182 jakw 120
    // Collected signal energy at higher frequencies
121
    cv::Mat energy0Primary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
122
    for(unsigned int i=0; i<nStepsPrimary-1; i++){
123
        cv::Mat magnitude;
124
        cv::magnitude(F0Primary[i*2 + 2], F0Primary[i*2 + 3], magnitude);
125
        cv::add(energy0Primary, magnitude, energy0Primary, cv::noArray(), CV_32F);
126
    }
127
 
128
    cv::Mat energy0Secondary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
129
    for(unsigned int i=0; i<nStepsSecondary-1; i++){
130
        cv::Mat magnitude;
131
        cv::magnitude(F0Secondary[i*2 + 2], F0Secondary[i*2 + 3], magnitude);
132
        cv::add(energy0Secondary, magnitude, energy0Secondary, cv::noArray(), CV_32F);
133
    }
134
 
185 jakw 135
    #ifdef QT_DEBUG
136
        cvtools::writeMat(up0Primary, "up0Primary.mat", "up0Primary");
137
        cvtools::writeMat(up0Secondary, "up0Secondary.mat", "up0Secondary");
138
        cvtools::writeMat(up0Equivalent, "up0Equivalent.mat", "up0Equivalent");
139
        cvtools::writeMat(up0, "up0.mat", "up0");
200 jakw 140
        cvtools::writeMat(amplitude0Primary, "amplitude0Primary.mat", "amplitude0Primary");
185 jakw 141
        cvtools::writeMat(energy0Primary, "energy0Primary.mat", "energy0Primary");
142
        cvtools::writeMat(energy0Secondary, "energy0Secondary.mat", "energy0Secondary");
143
    #endif
144
 
70 jakw 145
    // Decode camera1
178 jakw 146
    std::vector<cv::Mat> frames1Primary(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsPrimary);
147
    std::vector<cv::Mat> frames1Secondary(frames1Rect.begin()+2+nStepsPrimary, frames1Rect.end());
182 jakw 148
 
76 jakw 149
    std::vector<cv::Mat> F1Primary = getDFTComponents(frames1Primary);
74 jakw 150
    cv::Mat up1Primary;
76 jakw 151
    cv::phase(F1Primary[2], -F1Primary[3], up1Primary);
182 jakw 152
 
76 jakw 153
    std::vector<cv::Mat> F1Secondary = getDFTComponents(frames1Secondary);
154
    cv::Mat up1Secondary;
155
    cv::phase(F1Secondary[2], -F1Secondary[3], up1Secondary);
182 jakw 156
 
190 jakw 157
    cv::Mat up1Equivalent = up1Secondary - up1Primary;
192 jakw 158
    up1Equivalent = cvtools::modulo(up1Equivalent, 2.0*CV_PI);
190 jakw 159
    cv::Mat up1 = unwrapWithCue(up1Primary, up1Equivalent, nPeriodsPrimary);
192 jakw 160
    up1 *= screenCols/(2.0*CV_PI);
70 jakw 161
 
200 jakw 162
    // Signal energy at unit frequency
163
    cv::Mat amplitude1Primary, amplitude1Secondary;
164
    cv::magnitude(F1Primary[2], -F1Primary[3], amplitude1Primary);
165
    cv::magnitude(F1Secondary[2], -F1Secondary[3], amplitude1Secondary);
166
 
182 jakw 167
    // Collected signal energy at higher frequencies
168
    cv::Mat energy1Primary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
169
    for(unsigned int i=0; i<nStepsPrimary-1; i++){
170
        cv::Mat magnitude;
171
        cv::magnitude(F1Primary[i*2 + 2], F1Primary[i*2 + 3], magnitude);
172
        cv::add(energy1Primary, magnitude, energy1Primary, cv::noArray(), CV_32F);
173
    }
174
 
175
    cv::Mat energy1Secondary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
176
    for(unsigned int i=0; i<nStepsSecondary-1; i++){
177
        cv::Mat magnitude;
178
        cv::magnitude(F1Secondary[i*2 + 2], F1Secondary[i*2 + 3], magnitude);
179
        cv::add(energy1Secondary, magnitude, energy1Secondary, cv::noArray(), CV_32F);
180
    }
181
 
185 jakw 182
    #ifdef QT_DEBUG
183
        cvtools::writeMat(up1, "up1.mat", "up1");
184
    #endif
185
 
118 jakw 186
    // color debayer and remap
178 jakw 187
    cv::Mat color0, color1;
188
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
189
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
70 jakw 190
 
178 jakw 191
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
192
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
118 jakw 193
 
185 jakw 194
    #ifdef QT_DEBUG
182 jakw 195
        cvtools::writeMat(color0, "color0.mat", "color0");
196
        cvtools::writeMat(color1, "color1.mat", "color1");
197
    #endif
118 jakw 198
 
70 jakw 199
    // Occlusion masks
178 jakw 200
    cv::Mat occlusion0, occlusion1;
201
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
202
    occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
203
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
204
    occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
70 jakw 205
 
128 jakw 206
    // Threshold on energy at primary frequency
200 jakw 207
    occlusion0 = occlusion0 & (amplitude0Primary > 5.0*nStepsPrimary);
208
    occlusion1 = occlusion1 & (amplitude1Primary > 5.0*nStepsPrimary);
128 jakw 209
 
182 jakw 210
    // Threshold on energy ratios
200 jakw 211
    occlusion0 = occlusion0 & (amplitude0Primary > 0.85*energy0Primary);
212
    occlusion0 = occlusion0 & (amplitude0Secondary > 0.85*energy0Secondary);
74 jakw 213
 
200 jakw 214
    occlusion1 = occlusion1 & (amplitude1Primary > 0.85*energy1Primary);
215
    occlusion1 = occlusion1 & (amplitude1Secondary > 0.85*energy1Secondary);
70 jakw 216
 
182 jakw 217
//    // Erode occlusion masks
218
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
219
//    cv::erode(occlusion0, occlusion0, strel);
220
//    cv::erode(occlusion1, occlusion1, strel);
71 jakw 221
 
190 jakw 222
    // Threshold on gradient of phase
223
    cv::Mat edges0;
224
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
195 jakw 225
    occlusion0 = occlusion0 & (abs(edges0) < 10);
71 jakw 226
 
190 jakw 227
    cv::Mat edges1;
228
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
195 jakw 229
    occlusion1 = occlusion1 & (abs(edges1) < 10);
71 jakw 230
 
185 jakw 231
    #ifdef QT_DEBUG
195 jakw 232
        cvtools::writeMat(edges0, "edges0.mat", "edges0");
233
        cvtools::writeMat(edges1, "edges1.mat", "edges1");
185 jakw 234
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
182 jakw 235
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
236
    #endif
237
 
70 jakw 238
    // Match phase maps
239
 
240
    // camera0 against camera1
178 jakw 241
    std::vector<cv::Vec2f> q0, q1;
70 jakw 242
    for(int row=0; row<frameRectRows; row++){
243
        for(int col=0; col<frameRectCols; col++){
244
 
178 jakw 245
            if(!occlusion0.at<char>(row,col))
70 jakw 246
                continue;
247
 
178 jakw 248
            float up0i = up0.at<float>(row,col);
249
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 250
 
178 jakw 251
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 252
                    continue;
253
 
178 jakw 254
                float up1Left = up1.at<float>(row,col1);
255
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 256
 
190 jakw 257
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
70 jakw 258
 
259
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
260
 
178 jakw 261
                    q0.push_back(cv::Point2f(col, row));
262
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 263
 
264
                    break;
70 jakw 265
                }
266
            }
267
        }
268
    }
269
 
270
 
178 jakw 271
    int nMatches = q0.size();
74 jakw 272
 
70 jakw 273
    if(nMatches < 1){
274
        Q.resize(0);
275
        color.resize(0);
276
 
277
        return;
278
    }
279
 
280
    // Retrieve color information
281
    color.resize(nMatches);
282
    for(int i=0; i<nMatches; i++){
283
 
178 jakw 284
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
285
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
70 jakw 286
 
287
        color[i] = 0.5*c0 + 0.5*c1;
288
    }
289
 
290
    // Triangulate points
291
    cv::Mat QMatHomogenous, QMat;
178 jakw 292
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
70 jakw 293
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
294
 
295
    // Undo rectification
296
    cv::Mat R0Inv;
297
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
298
    QMat = R0Inv*QMat;
299
 
300
    cvtools::matToPoints3f(QMat, Q);
301
 
4 jakw 302
}