Subversion Repositories seema-scanner

Rev

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