Subversion Repositories seema-scanner

Rev

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