Subversion Repositories seema-scanner

Rev

Rev 187 | Rev 189 | 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
//
188 jakw 6
// The number of periods in the First and Second 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-First frequencies.
182 jakw 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
 
188 jakw 21
static unsigned int nStepsFirst = 8; // number of shifts/steps in First
22
static unsigned int nStepsSecond = 8; // number of shifts/steps in Second
23
static unsigned int nStepsThird = 8; // number of shifts/steps in Third
24
static float nPeriodsFirst = 24; // First period
25
static float nPeriodsSecond = 30; // First 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
188 jakw 30
    N = 2+nStepsFirst+nStepsSecond+nStepsThird;
72 jakw 31
 
188 jakw 32
    // Determine the Third period to fulfill the heterodyne condition
33
    float nPeriodsThird = 1 + 2*nPeriodsSecond - nPeriodsFirst;
182 jakw 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
 
188 jakw 46
    // First encoding patterns
47
    for(unsigned int i=0; i<nStepsFirst; i++){
48
        float phase = 2.0*pi/nStepsFirst * i;
49
        float pitch = screenCols/nPeriodsFirst;
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
 
188 jakw 55
    // Second encoding patterns
56
    for(unsigned int i=0; i<nStepsSecond; i++){
57
        float phase = 2.0*pi/nStepsSecond * i;
58
        float pitch = screenCols/nPeriodsSecond;
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
    }
188 jakw 63
    // Third encoding patterns
64
    for(unsigned int i=0; i<nStepsThird; i++){
65
        float phase = 2.0*pi/nStepsThird * i;
66
        float pitch = screenCols/nPeriodsThird;
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
188 jakw 115
    std::vector<cv::Mat> frames0First(frames0Rect.begin()+2, frames0Rect.begin()+2+nStepsFirst);
116
    std::vector<cv::Mat> frames0Second(frames0Rect.begin()+2+nStepsFirst, frames0Rect.end()-nStepsThird);
117
    std::vector<cv::Mat> frames0Third(frames0Rect.end()-nStepsThird, frames0Rect.end());
129 jakw 118
 
188 jakw 119
    std::vector<cv::Mat> F0First = getDFTComponents(frames0First);
120
    cv::Mat up0First;
121
    cv::phase(F0First[2], -F0First[3], up0First);
122
    std::vector<cv::Mat> F0Second = getDFTComponents(frames0Second);
123
    cv::Mat up0Second;
124
    cv::phase(F0Second[2], -F0Second[3], up0Second);
125
    std::vector<cv::Mat> F0Third = getDFTComponents(frames0Third);
126
    cv::Mat up0Third;
127
    cv::phase(F0Third[2], -F0Third[3], up0Third);
128 jakw 128
 
188 jakw 129
    cv::Mat up0EquivalentPS = up0First - up0Second;
182 jakw 130
    up0EquivalentPS = cvtools::modulo(up0EquivalentPS, 2.0*pi);
131
 
188 jakw 132
    cv::Mat up0EquivalentPT = up0First - up0Third;
187 jakw 133
    up0EquivalentPT = cvtools::modulo(up0EquivalentPT, 2.0*pi);
182 jakw 134
 
188 jakw 135
    cv::Mat up0EquivalentPST = up0EquivalentPS - up0EquivalentPT;
136
    up0EquivalentPST = cvtools::modulo(up0EquivalentPST, 2.0*pi);
182 jakw 137
 
188 jakw 138
        // TODO: we should use backward phase unwrapping (Song Zhang term)...
139
 
140
    cv::Mat up0 = unwrapWithCue(up0First, up0EquivalentPST, (float)screenCols/nPeriodsFirst);
128 jakw 141
    up0 *= screenCols/(2.0*pi);
142
    cv::Mat amplitude0;
188 jakw 143
    cv::magnitude(F0First[2], -F0First[3], amplitude0);
70 jakw 144
 
145
    // Decode camera1
188 jakw 146
    std::vector<cv::Mat> frames1First(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsFirst);
147
    std::vector<cv::Mat> frames1Second(frames1Rect.begin()+2+nStepsFirst, frames1Rect.end()-nStepsThird);
148
    std::vector<cv::Mat> frames1Third(frames1Rect.end()-nStepsThird, frames1Rect.end());
129 jakw 149
 
188 jakw 150
    std::vector<cv::Mat> F1First = getDFTComponents(frames1First);
151
    cv::Mat up1First;
152
    cv::phase(F1First[2], -F1First[3], up1First);
153
    std::vector<cv::Mat> F1Second = getDFTComponents(frames1Second);
154
    cv::Mat up1Second;
155
    cv::phase(F1Second[2], -F1Second[3], up1Second);
156
    std::vector<cv::Mat> F1Third = getDFTComponents(frames1Third);
157
    cv::Mat up1Third;
158
    cv::phase(F1Third[2], -F1Third[3], up1Third);
128 jakw 159
 
188 jakw 160
    cv::Mat up1EquivalentPS = up1First - up1Second;
182 jakw 161
    up1EquivalentPS = cvtools::modulo(up1EquivalentPS, 2.0*pi);
162
 
188 jakw 163
    cv::Mat up1EquivalentST = up1Second - up1Third;
182 jakw 164
    up1EquivalentST = cvtools::modulo(up1EquivalentST, 2.0*pi);
165
 
188 jakw 166
    cv::Mat up1EquivalentPST = up1EquivalentPS - up1EquivalentST;
167
    up1EquivalentPST = cvtools::modulo(up1EquivalentPST, 2.0*pi);
182 jakw 168
 
188 jakw 169
    cv::Mat up1 = unwrapWithCue(up1First, up1EquivalentPST, (float)screenCols/nPeriodsFirst);
128 jakw 170
    up1 *= screenCols/(2.0*pi);
171
    cv::Mat amplitude1;
188 jakw 172
    cv::magnitude(F1First[2], -F1First[3], amplitude1);
70 jakw 173
 
185 jakw 174
    #ifdef QT_DEBUG
188 jakw 175
        cvtools::writeMat(up0First, "up0First.mat", "up0First");
176
        cvtools::writeMat(up0Second, "up0Second.mat", "up0Second");
177
        cvtools::writeMat(up0Third, "up0Third.mat", "up0Third");
182 jakw 178
        cvtools::writeMat(up0EquivalentPS, "up0EquivalentPS.mat", "up0EquivalentPS");
187 jakw 179
        cvtools::writeMat(up0EquivalentPT, "up0EquivalentPT.mat", "up0EquivalentPT");
188 jakw 180
        cvtools::writeMat(up0EquivalentPST, "up0EquivalentPST.mat", "up0EquivalentPST");
182 jakw 181
        cvtools::writeMat(up0, "up0.mat", "up0");
182
        cvtools::writeMat(up1, "up1.mat", "up1");
183
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
71 jakw 184
 
182 jakw 185
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
186
        cvtools::writeMat(amplitude1, "amplitude1.mat", "amplitude1");
187
    #endif
70 jakw 188
 
187 jakw 189
    // color debayer and remap
179 jakw 190
    cv::Mat color0, color1;
191
    cv::cvtColor(frames0[0], color0, CV_BayerBG2RGB);
187 jakw 192
    cv::remap(color0, color0, map0X, map0Y, CV_INTER_LINEAR);
193
 
179 jakw 194
    cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
187 jakw 195
    cv::remap(color1, color1, map1X, map1Y, CV_INTER_LINEAR);
70 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
70 jakw 201
 
202
    // Occlusion masks
179 jakw 203
    cv::Mat occlusion0, occlusion1;
204
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
205
    occlusion0 = (occlusion0 > 5) & (occlusion0 < 250);
206
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
207
    occlusion1 = (occlusion1 > 5) & (occlusion1 < 250);
70 jakw 208
 
71 jakw 209
    // Threshold on gradient of phase
210
    cv::Mat edges0;
179 jakw 211
    cv::Sobel(up0, edges0, -1, 1, 1, 5);
212
    occlusion0 = occlusion0 & (abs(edges0) < 150);
71 jakw 213
    cv::Mat edges1;
179 jakw 214
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
215
    occlusion1 = occlusion1 & (abs(edges1) < 150);
71 jakw 216
 
185 jakw 217
    #ifdef QT_DEBUG
182 jakw 218
        cvtools::writeMat(edges0, "edges0.mat", "edges0");
219
        cvtools::writeMat(edges1, "edges1.mat", "edges1");
220
    #endif
71 jakw 221
 
187 jakw 222
    #ifdef QT_DEBUG
223
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
224
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
225
    #endif
226
 
70 jakw 227
    // Match phase maps
228
    int frameRectRows = map0X.rows;
229
    int frameRectCols = map0X.cols;
230
 
231
    // camera0 against camera1
179 jakw 232
    std::vector<cv::Vec2f> q0, q1;
70 jakw 233
    for(int row=0; row<frameRectRows; row++){
234
        for(int col=0; col<frameRectCols; col++){
235
 
179 jakw 236
            if(!occlusion0.at<char>(row,col))
70 jakw 237
                continue;
238
 
179 jakw 239
            float up0i = up0.at<float>(row,col);
240
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 241
 
179 jakw 242
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 243
                    continue;
244
 
179 jakw 245
                float up1Left = up1.at<float>(row,col1);
246
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 247
 
131 jakw 248
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0)){
70 jakw 249
 
250
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
251
 
179 jakw 252
                    q0.push_back(cv::Point2f(col, row));
253
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 254
 
255
                    break;
70 jakw 256
                }
257
            }
258
        }
259
    }
260
 
179 jakw 261
    int nMatches = q0.size();
70 jakw 262
 
263
    if(nMatches < 1){
264
        Q.resize(0);
265
        color.resize(0);
266
 
267
        return;
268
    }
269
 
270
    // Retrieve color information
271
    color.resize(nMatches);
272
    for(int i=0; i<nMatches; i++){
273
 
179 jakw 274
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
275
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
70 jakw 276
 
277
        color[i] = 0.5*c0 + 0.5*c1;
278
    }
279
 
280
    // Triangulate points
281
    cv::Mat QMatHomogenous, QMat;
179 jakw 282
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
70 jakw 283
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
284
 
285
    // Undo rectification
286
    cv::Mat R0Inv;
287
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
288
    QMat = R0Inv*QMat;
289
 
290
    cvtools::matToPoints3f(QMat, Q);
291
 
4 jakw 292
}