Subversion Repositories seema-scanner

Rev

Rev 179 | Rev 185 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 179 Rev 182
Line -... Line 1...
-
 
1
//
-
 
2
// Three 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
//
-
 
6
// The number of periods in the primary and secondary frequencies can be chosen freely, but small changes can have a considerable impact on quality.
-
 
7
// 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.
-
 
8
//
-
 
9
 
-
 
10
 
1
#include "AlgorithmPhaseShiftThreeFreq.h"
11
#include "AlgorithmPhaseShiftThreeFreq.h"
2
#include <math.h>
12
#include <math.h>
3
 
13
 
4
#include "cvtools.h"
14
#include "cvtools.h"
-
 
15
#include "algorithmtools.h"
5
 
16
 
6
#ifndef M_PI
17
#ifndef M_PI
7
    #define M_PI 3.14159265358979323846
18
    #define M_PI 3.14159265358979323846
8
#endif
19
#endif
9
 
20
 
10
static unsigned int nStepsPrimary = 32; // number of shifts/steps in primary
21
static unsigned int nStepsPrimary = 8; // number of shifts/steps in primary
11
static unsigned int nStepsSecondary = 16; // number of shifts/steps in secondary
22
static unsigned int nStepsSecondary = 8; // number of shifts/steps in secondary
12
static unsigned int nStepsTertiary = 16; // number of shifts/steps in tertiary
23
static unsigned int nStepsTertiary = 8; // number of shifts/steps in tertiary
13
static float nPeriodPrimary = 256; // number of primary periods
24
static float nPeriodsPrimary = 24; // primary period
14
static float nPeriodSecondary = 16; // number of secondary periods
25
static float nPeriodsSecondary = 30; // primary period
15
 
-
 
16
// Algorithm
-
 
17
static cv::Mat computePhaseVector(unsigned int length, float phase, float pitch){
-
 
18
 
-
 
19
    cv::Mat phaseVector(length, 1, CV_8UC3);
-
 
20
    //phaseVector.setTo(0);
-
 
21
 
-
 
22
    const float pi = M_PI;
-
 
23
 
-
 
24
    // Loop through vector
-
 
25
    for(int i=0; i<phaseVector.rows; i++){
-
 
26
        // Amplitude of channels
-
 
27
        float amp = 0.5*(1+cos(2*pi*i/pitch - phase));
-
 
28
        phaseVector.at<cv::Vec3b>(i, 0) = cv::Vec3b(255.0*amp, 255.0*amp, 255.0*amp);
-
 
29
    }
-
 
30
 
-
 
31
    return phaseVector;
-
 
32
}
-
 
33
 
26
 
34
AlgorithmPhaseShiftThreeFreq::AlgorithmPhaseShiftThreeFreq(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
27
AlgorithmPhaseShiftThreeFreq::AlgorithmPhaseShiftThreeFreq(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
35
 
28
 
36
    // Set N
29
    // Set N
37
    N = 2+nStepsPrimary+nStepsSecondary+nStepsTertiary;
30
    N = 2+nStepsPrimary+nStepsSecondary+nStepsTertiary;
38
 
31
 
-
 
32
    // Determine the tertiary period to fulfill the heterodyne condition
-
 
33
    float nPeriodsTertiary = (screenCols*nPeriodsPrimary*nPeriodsSecondary)/(nPeriodsPrimary*nPeriodsSecondary+2*screenCols*nPeriodsPrimary-screenCols*nPeriodsSecondary);
-
 
34
 
39
    // all on pattern
35
    // all on pattern
40
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
36
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
41
    patterns.push_back(allOn);
37
    patterns.push_back(allOn);
42
 
38
 
43
    // all off pattern
39
    // all off pattern
Line 48... Line 44...
48
    const float pi = M_PI;
44
    const float pi = M_PI;
49
 
45
 
50
    // Primary encoding patterns
46
    // Primary encoding patterns
51
    for(unsigned int i=0; i<nStepsPrimary; i++){
47
    for(unsigned int i=0; i<nStepsPrimary; i++){
52
        float phase = 2.0*pi/nStepsPrimary * i;
48
        float phase = 2.0*pi/nStepsPrimary * i;
53
        float pitch = screenCols/nPeriodPrimary;
49
        float pitch = screenCols/nPeriodsPrimary;
54
        cv::Mat patternI(1,1,CV_8U);
50
        cv::Mat patternI(1,1,CV_8U);
55
        patternI = computePhaseVector(screenCols, phase, pitch);
51
        patternI = computePhaseVector(screenCols, phase, pitch);
56
        patterns.push_back(patternI.t());
52
        patterns.push_back(patternI.t());
57
    }
53
    }
58
 
54
 
59
    // Secondary encoding patterns
55
    // Secondary encoding patterns
60
    for(unsigned int i=0; i<nStepsSecondary; i++){
56
    for(unsigned int i=0; i<nStepsSecondary; i++){
61
        float phase = 2.0*pi/nStepsSecondary * i;
57
        float phase = 2.0*pi/nStepsSecondary * i;
62
        float pitch = screenCols/nPeriodSecondary;
58
        float pitch = screenCols/nPeriodsSecondary;
63
        cv::Mat patternI(1,1,CV_8U);
59
        cv::Mat patternI(1,1,CV_8U);
64
        patternI = computePhaseVector(screenCols, phase, pitch);
60
        patternI = computePhaseVector(screenCols, phase, pitch);
65
        patterns.push_back(patternI.t());
61
        patterns.push_back(patternI.t());
66
    }
62
    }
67
    // Tertiary encoding patterns
63
    // Tertiary encoding patterns
68
    for(unsigned int i=0; i<nStepsTertiary; i++){
64
    for(unsigned int i=0; i<nStepsTertiary; i++){
69
        float phase = 2.0*pi/nStepsTertiary * i;
65
        float phase = 2.0*pi/nStepsTertiary * i;
70
        float pitch = screenCols;
66
        float pitch = screenCols/nPeriodsTertiary;
71
        cv::Mat patternI(1,1,CV_8U);
67
        cv::Mat patternI(1,1,CV_8U);
72
        patternI = computePhaseVector(screenCols, phase, pitch);
68
        patternI = computePhaseVector(screenCols, phase, pitch);
73
        patterns.push_back(patternI.t());
69
        patterns.push_back(patternI.t());
74
    }
70
    }
75
 
71
 
Line 77... Line 73...
77
 
73
 
78
cv::Mat AlgorithmPhaseShiftThreeFreq::getEncodingPattern(unsigned int depth){
74
cv::Mat AlgorithmPhaseShiftThreeFreq::getEncodingPattern(unsigned int depth){
79
    return patterns[depth];
75
    return patterns[depth];
80
}
76
}
81
 
77
 
82
 
-
 
83
//// Absolute phase from 3 frames
-
 
84
//static cv::Mat getPhase(const cv::Mat I1, const cv::Mat I2, const cv::Mat I3){
-
 
85
 
-
 
86
//    cv::Mat_<float> I1_(I1);
-
 
87
//    cv::Mat_<float> I2_(I2);
-
 
88
//    cv::Mat_<float> I3_(I3);
-
 
89
 
-
 
90
//    cv::Mat phase;
-
 
91
 
-
 
92
//    // One call approach
-
 
93
//    cv::phase(2.0*I1_-I3_-I2_, sqrt(3.0)*(I2_-I3_), phase);
-
 
94
//    return phase;
-
 
95
 
-
 
96
//}
-
 
97
 
-
 
98
// Phase unwrapping by means of a phase cue
-
 
99
static cv::Mat unwrapWithCue(const cv::Mat up, const cv::Mat upCue, float nPhases){
-
 
100
 
-
 
101
    const float pi = M_PI;
-
 
102
 
-
 
103
    // Determine number of jumps
-
 
104
    cv::Mat P = (upCue*nPhases-up)/(2.0*pi);
-
 
105
 
-
 
106
    // Round to integers
-
 
107
    P.convertTo(P, CV_8U);
-
 
108
    P.convertTo(P, CV_32F);
-
 
109
 
-
 
110
    // Add to phase
-
 
111
    cv::Mat upUnwrapped = up + P*2*pi;
-
 
112
 
-
 
113
    // Scale to range [0; 2pi]
-
 
114
    upUnwrapped *= 1.0/nPhases;
-
 
115
 
-
 
116
    return upUnwrapped;
-
 
117
}
-
 
118
 
-
 
119
// Absolute phase and magnitude from N frames
-
 
120
static std::vector<cv::Mat> getDFTComponents(const std::vector<cv::Mat> frames){
-
 
121
 
-
 
122
    unsigned int N = frames.size();
-
 
123
 
-
 
124
//    std::vector<cv::Mat> framesReverse = frames;
-
 
125
//    std::reverse(framesReverse.begin(), framesReverse.end());
-
 
126
 
-
 
127
    // DFT approach
-
 
128
    cv::Mat I;
-
 
129
    cv::merge(frames, I);
-
 
130
    unsigned int w = I.cols;
-
 
131
    unsigned int h = I.rows;
-
 
132
    I = I.reshape(1, h*w);
-
 
133
    I.convertTo(I, CV_32F);
-
 
134
    cv::Mat fI;
-
 
135
    cv::dft(I, fI, cv::DFT_ROWS + cv::DFT_COMPLEX_OUTPUT);
-
 
136
    fI = fI.reshape(N*2, h);
-
 
137
 
-
 
138
    std::vector<cv::Mat> fIcomp;
-
 
139
    cv::split(fI, fIcomp);
-
 
140
 
-
 
141
    return fIcomp;
-
 
142
 
-
 
143
}
-
 
144
 
-
 
145
void AlgorithmPhaseShiftThreeFreq::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){
78
void AlgorithmPhaseShiftThreeFreq::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){
146
 
79
 
147
    const float pi = M_PI;
80
    const float pi = M_PI;
148
 
81
 
149
    assert(frames0.size() == N);
82
    assert(frames0.size() == N);
Line 191... Line 124...
191
    cv::phase(F0Secondary[2], -F0Secondary[3], up0Secondary);
124
    cv::phase(F0Secondary[2], -F0Secondary[3], up0Secondary);
192
    std::vector<cv::Mat> F0Tertiary = getDFTComponents(frames0Tertiary);
125
    std::vector<cv::Mat> F0Tertiary = getDFTComponents(frames0Tertiary);
193
    cv::Mat up0Tertiary;
126
    cv::Mat up0Tertiary;
194
    cv::phase(F0Tertiary[2], -F0Tertiary[3], up0Tertiary);
127
    cv::phase(F0Tertiary[2], -F0Tertiary[3], up0Tertiary);
195
 
128
 
-
 
129
    cv::Mat up0EquivalentPS = up0Primary - up0Secondary;
-
 
130
    up0EquivalentPS = cvtools::modulo(up0EquivalentPS, 2.0*pi);
-
 
131
 
196
    cv::Mat up0Unwrap = unwrapWithCue(up0Secondary, up0Tertiary, nPeriodSecondary);
132
    cv::Mat up0EquivalentST = up0Secondary - up0Tertiary;
-
 
133
    up0EquivalentST = cvtools::modulo(up0EquivalentST, 2.0*pi);
-
 
134
 
-
 
135
    cv::Mat up0Equivalent = up0EquivalentPS - up0EquivalentST;
-
 
136
    up0Equivalent = cvtools::modulo(up0Equivalent, 2.0*pi);
-
 
137
 
197
    cv::Mat up0 = unwrapWithCue(up0Primary, up0Unwrap, nPeriodPrimary);
138
    cv::Mat up0 = unwrapWithCue(up0Primary, up0Equivalent, (float)screenCols/nPeriodsPrimary);
198
    up0 *= screenCols/(2.0*pi);
139
    up0 *= screenCols/(2.0*pi);
199
    cv::Mat amplitude0;
140
    cv::Mat amplitude0;
200
    cv::magnitude(F0Primary[2], -F0Primary[3], amplitude0);
141
    cv::magnitude(F0Primary[2], -F0Primary[3], amplitude0);
201
 
142
 
202
    // Decode camera1
143
    // Decode camera1
Line 212... Line 153...
212
    cv::phase(F1Secondary[2], -F1Secondary[3], up1Secondary);
153
    cv::phase(F1Secondary[2], -F1Secondary[3], up1Secondary);
213
    std::vector<cv::Mat> F1Tertiary = getDFTComponents(frames1Tertiary);
154
    std::vector<cv::Mat> F1Tertiary = getDFTComponents(frames1Tertiary);
214
    cv::Mat up1Tertiary;
155
    cv::Mat up1Tertiary;
215
    cv::phase(F1Tertiary[2], -F1Tertiary[3], up1Tertiary);
156
    cv::phase(F1Tertiary[2], -F1Tertiary[3], up1Tertiary);
216
 
157
 
-
 
158
    cv::Mat up1EquivalentPS = up1Primary - up1Secondary;
-
 
159
    up1EquivalentPS = cvtools::modulo(up1EquivalentPS, 2.0*pi);
-
 
160
 
217
    cv::Mat up1Unwrap = unwrapWithCue(up1Secondary, up1Tertiary, nPeriodSecondary);
161
    cv::Mat up1EquivalentST = up1Secondary - up1Tertiary;
-
 
162
    up1EquivalentST = cvtools::modulo(up1EquivalentST, 2.0*pi);
-
 
163
 
-
 
164
    cv::Mat up1Equivalent = up1EquivalentPS - up1EquivalentST;
-
 
165
    up1Equivalent = cvtools::modulo(up1Equivalent, 2.0*pi);
-
 
166
 
218
    cv::Mat up1 = unwrapWithCue(up1Primary, up1Unwrap, nPeriodPrimary);
167
    cv::Mat up1 = unwrapWithCue(up1Primary, up1Equivalent, (float)screenCols/nPeriodsPrimary);
219
    up1 *= screenCols/(2.0*pi);
168
    up1 *= screenCols/(2.0*pi);
220
    cv::Mat amplitude1;
169
    cv::Mat amplitude1;
221
    cv::magnitude(F1Primary[2], -F1Primary[3], amplitude1);
170
    cv::magnitude(F1Primary[2], -F1Primary[3], amplitude1);
222
 
171
 
-
 
172
    #ifdef Q_DEBUG
223
//cvtools::writeMat(up0Primary, "up0Primary.mat", "up0Primary");
173
        cvtools::writeMat(up0Primary, "up0Primary.mat", "up0Primary");
224
//cvtools::writeMat(up0Secondary, "up0Secondary.mat", "up0Secondary");
174
        cvtools::writeMat(up0Secondary, "up0Secondary.mat", "up0Secondary");
225
//cvtools::writeMat(up0Tertiary, "up0Tertiary.mat", "up0Tertiary");
175
        cvtools::writeMat(up0Tertiary, "up0Tertiary.mat", "up0Tertiary");
-
 
176
        cvtools::writeMat(up0EquivalentPS, "up0EquivalentPS.mat", "up0EquivalentPS");
226
//cvtools::writeMat(up0Unwrap, "up0Unwrap.mat", "up0Unwrap");
177
        cvtools::writeMat(up0EquivalentST, "up0EquivalentST.mat", "up0EquivalentST");
227
//cvtools::writeMat(up0, "up0.mat", "up0");
178
        cvtools::writeMat(up0, "up0.mat", "up0");
228
//cvtools::writeMat(up1, "up1.mat", "up1");
179
        cvtools::writeMat(up1, "up1.mat", "up1");
229
//cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
180
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
230
 
181
 
231
//cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
182
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
232
//cvtools::writeMat(amplitude1, "amplitude1.mat", "amplitude1");
183
        cvtools::writeMat(amplitude1, "amplitude1.mat", "amplitude1");
-
 
184
    #endif
233
 
185
 
234
    // Color debayer and remap
186
    // Color debayer and remap
235
    cv::Mat color0, color1;
187
    cv::Mat color0, color1;
236
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
188
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
237
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
189
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
238
 
190
 
-
 
191
    #ifdef Q_DEBUG
239
//cvtools::writeMat(color0, "color0.mat", "color0");
192
        cvtools::writeMat(color0, "color0.mat", "color0");
240
//cvtools::writeMat(color1, "color1.mat", "color1");
193
        cvtools::writeMat(color1, "color1.mat", "color1");
-
 
194
    #endif
241
 
195
 
242
    // Occlusion masks
196
    // Occlusion masks
243
    cv::Mat occlusion0, occlusion1;
197
    cv::Mat occlusion0, occlusion1;
244
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
198
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
245
    occlusion0 = (occlusion0 > 5) & (occlusion0 < 250);
199
    occlusion0 = (occlusion0 > 5) & (occlusion0 < 250);
246
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
200
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
247
    occlusion1 = (occlusion1 > 5) & (occlusion1 < 250);
201
    occlusion1 = (occlusion1 > 5) & (occlusion1 < 250);
248
 
202
 
249
//    // Threshold on energy at primary frequency
203
    #ifdef Q_DEBUG
250
//    occlusion0 = occlusion0 & (amplitude0 > 5.0*nStepsPrimary);
-
 
251
//    occlusion1 = occlusion1 & (amplitude1 > 5.0*nStepsPrimary);
-
 
252
 
-
 
253
//cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
-
 
254
//cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
-
 
255
 
-
 
256
//    // Erode occlusion masks
204
        // Erode occlusion masks
257
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
205
        cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
258
//    cv::erode(occlusion0, occlusion0, strel);
206
        cv::erode(occlusion0, occlusion0, strel);
259
//    cv::erode(occlusion1, occlusion1, strel);
207
        cv::erode(occlusion1, occlusion1, strel);
-
 
208
    #endif
260
 
209
 
261
    // Threshold on gradient of phase
210
    // Threshold on gradient of phase
262
    cv::Mat edges0;
211
    cv::Mat edges0;
263
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
212
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
264
    occlusion0 = occlusion0 & (abs(edges0) < 150);
213
    occlusion0 = occlusion0 & (abs(edges0) < 150);
265
    cv::Mat edges1;
214
    cv::Mat edges1;
266
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
215
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
267
    occlusion1 = occlusion1 & (abs(edges1) < 150);
216
    occlusion1 = occlusion1 & (abs(edges1) < 150);
268
 
217
 
-
 
218
    #ifdef Q_DEBUG
269
//cvtools::writeMat(edges0, "edges0.mat", "edges0");
219
        cvtools::writeMat(edges0, "edges0.mat", "edges0");
270
//cvtools::writeMat(edges1, "edges1.mat", "edges1");
220
        cvtools::writeMat(edges1, "edges1.mat", "edges1");
-
 
221
    #endif
271
 
222
 
272
    // Match phase maps
223
    // Match phase maps
273
    int frameRectRows = map0X.rows;
224
    int frameRectRows = map0X.rows;
274
    int frameRectCols = map0X.cols;
225
    int frameRectCols = map0X.cols;
275
 
226