Subversion Repositories seema-scanner

Rev

Rev 179 | Rev 185 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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