Subversion Repositories seema-scanner

Rev

Rev 181 | Rev 185 | 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
182 jakw 23
static float nPeriodsPrimary = 48; // 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
 
74 jakw 30
    // Determine the secondary (wider) period
182 jakw 31
    float nPeriodsSecondary = (screenCols*nPeriodsPrimary)/(screenCols-nPeriodsPrimary);
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;
182 jakw 47
        float pitch = 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;
182 jakw 56
        float pitch = 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
 
74 jakw 119
    cv::Mat up0Equivalent = up0Primary - up0Secondary;
128 jakw 120
    up0Equivalent = cvtools::modulo(up0Equivalent, 2.0*pi);
182 jakw 121
    cv::Mat up0 = unwrapWithCue(up0Primary, up0Equivalent, (float)screenCols/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
 
70 jakw 141
    // Decode camera1
178 jakw 142
    std::vector<cv::Mat> frames1Primary(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsPrimary);
143
    std::vector<cv::Mat> frames1Secondary(frames1Rect.begin()+2+nStepsPrimary, frames1Rect.end());
182 jakw 144
 
76 jakw 145
    std::vector<cv::Mat> F1Primary = getDFTComponents(frames1Primary);
74 jakw 146
    cv::Mat up1Primary;
76 jakw 147
    cv::phase(F1Primary[2], -F1Primary[3], up1Primary);
182 jakw 148
 
76 jakw 149
    std::vector<cv::Mat> F1Secondary = getDFTComponents(frames1Secondary);
150
    cv::Mat up1Secondary;
151
    cv::phase(F1Secondary[2], -F1Secondary[3], up1Secondary);
182 jakw 152
 
74 jakw 153
    cv::Mat up1Equivalent = up1Primary - up1Secondary;
128 jakw 154
    up1Equivalent = cvtools::modulo(up1Equivalent, 2.0*pi);
182 jakw 155
    cv::Mat up1 = unwrapWithCue(up1Primary, up1Equivalent, (float)screenCols/nPeriodsPrimary);
128 jakw 156
    up1 *= screenCols/(2.0*pi);
157
    cv::Mat amplitude1;
158
    cv::magnitude(F1Primary[2], -F1Primary[3], amplitude1);
70 jakw 159
 
182 jakw 160
    #ifdef Q_DEBUG
161
        cvtools::writeMat(up0Primary, "up0Primary.mat", "up0Primary");
162
        cvtools::writeMat(up0Secondary, "up0Secondary.mat", "up0Secondary");
163
        cvtools::writeMat(up0Equivalent, "up0Equivalent.mat", "up0Equivalent");
164
        cvtools::writeMat(up0, "up0.mat", "up0");
165
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
166
    #endif
71 jakw 167
 
182 jakw 168
    // Collected signal energy at higher frequencies
169
    cv::Mat energy1Primary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
170
    for(unsigned int i=0; i<nStepsPrimary-1; i++){
171
        cv::Mat magnitude;
172
        cv::magnitude(F1Primary[i*2 + 2], F1Primary[i*2 + 3], magnitude);
173
        cv::add(energy1Primary, magnitude, energy1Primary, cv::noArray(), CV_32F);
174
    }
175
 
176
    cv::Mat energy1Secondary(frameRectRows, frameRectCols, CV_32F, cv::Scalar(0.0));
177
    for(unsigned int i=0; i<nStepsSecondary-1; i++){
178
        cv::Mat magnitude;
179
        cv::magnitude(F1Secondary[i*2 + 2], F1Secondary[i*2 + 3], magnitude);
180
        cv::add(energy1Secondary, magnitude, energy1Secondary, cv::noArray(), CV_32F);
181
    }
182
 
118 jakw 183
    // color debayer and remap
178 jakw 184
    cv::Mat color0, color1;
185
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
186
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
70 jakw 187
 
178 jakw 188
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
189
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
118 jakw 190
 
182 jakw 191
    #ifdef Q_DEBUG
192
        cvtools::writeMat(color0, "color0.mat", "color0");
193
        cvtools::writeMat(color1, "color1.mat", "color1");
194
    #endif
118 jakw 195
 
70 jakw 196
    // Occlusion masks
178 jakw 197
    cv::Mat occlusion0, occlusion1;
198
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
199
    occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
200
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
201
    occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
70 jakw 202
 
128 jakw 203
    // Threshold on energy at primary frequency
178 jakw 204
    occlusion0 = occlusion0 & (amplitude0 > 5.0*nStepsPrimary);
205
    occlusion1 = occlusion1 & (amplitude1 > 5.0*nStepsPrimary);
128 jakw 206
 
182 jakw 207
    // Threshold on energy ratios
208
    occlusion0 = occlusion0 & (amplitude0 > 0.85*energy0Primary);
209
    occlusion0 = occlusion0 & (amplitude0 > 0.85*energy0Secondary);
74 jakw 210
 
182 jakw 211
    occlusion1 = occlusion1 & (amplitude1 > 0.85*energy1Primary);
212
    occlusion1 = occlusion1 & (amplitude1 > 0.85*energy1Secondary);
70 jakw 213
 
182 jakw 214
//    // Erode occlusion masks
215
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
216
//    cv::erode(occlusion0, occlusion0, strel);
217
//    cv::erode(occlusion1, occlusion1, strel);
71 jakw 218
 
182 jakw 219
//    // Threshold on gradient of phase
220
//    cv::Mat edges0;
221
//    cv::Sobel(up0, edges0, -1, 1, 1, 5);
222
//    occlusion0 = occlusion0 & (abs(edges0) < 150);
71 jakw 223
 
182 jakw 224
//    cv::Mat edges1;
225
//    cv::Sobel(up1, edges1, -1, 1, 1, 5);
226
//    occlusion1 = occlusion1 & (abs(edges1) < 150);
71 jakw 227
 
182 jakw 228
    #ifdef Q_DEBUG
229
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
230
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
231
    #endif
232
 
70 jakw 233
    // Match phase maps
234
 
235
    // camera0 against camera1
178 jakw 236
    std::vector<cv::Vec2f> q0, q1;
70 jakw 237
    for(int row=0; row<frameRectRows; row++){
238
        for(int col=0; col<frameRectCols; col++){
239
 
178 jakw 240
            if(!occlusion0.at<char>(row,col))
70 jakw 241
                continue;
242
 
178 jakw 243
            float up0i = up0.at<float>(row,col);
244
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 245
 
178 jakw 246
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 247
                    continue;
248
 
178 jakw 249
                float up1Left = up1.at<float>(row,col1);
250
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 251
 
74 jakw 252
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1) && (up1Right-up0i < 1)){
70 jakw 253
 
254
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
255
 
178 jakw 256
                    q0.push_back(cv::Point2f(col, row));
257
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 258
 
259
                    break;
70 jakw 260
                }
261
            }
262
        }
263
    }
264
 
265
 
178 jakw 266
    int nMatches = q0.size();
74 jakw 267
 
70 jakw 268
    if(nMatches < 1){
269
        Q.resize(0);
270
        color.resize(0);
271
 
272
        return;
273
    }
274
 
275
    // Retrieve color information
276
    color.resize(nMatches);
277
    for(int i=0; i<nMatches; i++){
278
 
178 jakw 279
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
280
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
70 jakw 281
 
282
        color[i] = 0.5*c0 + 0.5*c1;
283
    }
284
 
285
    // Triangulate points
286
    cv::Mat QMatHomogenous, QMat;
178 jakw 287
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
70 jakw 288
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
289
 
290
    // Undo rectification
291
    cv::Mat R0Inv;
292
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
293
    QMat = R0Inv*QMat;
294
 
295
    cvtools::matToPoints3f(QMat, Q);
296
 
4 jakw 297
}