Subversion Repositories seema-scanner

Rev

Rev 236 | 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
 
188 jakw 17
static unsigned int nStepsFirst = 8; // number of shifts/steps in First
18
static unsigned int nStepsSecond = 8; // number of shifts/steps in Second
19
static unsigned int nStepsThird = 8; // number of shifts/steps in Third
20
static float nPeriodsFirst = 24; // First period
21
static float nPeriodsSecond = 30; // First period
4 jakw 22
 
128 jakw 23
AlgorithmPhaseShiftThreeFreq::AlgorithmPhaseShiftThreeFreq(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
4 jakw 24
 
72 jakw 25
    // Set N
188 jakw 26
    N = 2+nStepsFirst+nStepsSecond+nStepsThird;
72 jakw 27
 
190 jakw 28
    // Determine the third number of periods to fulfill the heterodyne condition
188 jakw 29
    float nPeriodsThird = 1 + 2*nPeriodsSecond - nPeriodsFirst;
182 jakw 30
 
70 jakw 31
    // all on pattern
32
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
33
    patterns.push_back(allOn);
34
 
35
    // all off pattern
36
    cv::Mat allOff(1, screenCols, CV_8UC3, cv::Scalar::all(0));
37
    patterns.push_back(allOff);
38
 
4 jakw 39
    // Precompute encoded patterns
40
 
188 jakw 41
    // First encoding patterns
42
    for(unsigned int i=0; i<nStepsFirst; i++){
192 jakw 43
        float phase = 2.0*CV_PI/nStepsFirst * i;
188 jakw 44
        float pitch = screenCols/nPeriodsFirst;
70 jakw 45
        cv::Mat patternI(1,1,CV_8U);
46
        patternI = computePhaseVector(screenCols, phase, pitch);
47
        patterns.push_back(patternI.t());
48
    }
4 jakw 49
 
188 jakw 50
    // Second encoding patterns
51
    for(unsigned int i=0; i<nStepsSecond; i++){
192 jakw 52
        float phase = 2.0*CV_PI/nStepsSecond * i;
188 jakw 53
        float pitch = screenCols/nPeriodsSecond;
72 jakw 54
        cv::Mat patternI(1,1,CV_8U);
70 jakw 55
        patternI = computePhaseVector(screenCols, phase, pitch);
56
        patterns.push_back(patternI.t());
4 jakw 57
    }
188 jakw 58
    // Third encoding patterns
59
    for(unsigned int i=0; i<nStepsThird; i++){
192 jakw 60
        float phase = 2.0*CV_PI/nStepsThird * i;
188 jakw 61
        float pitch = screenCols/nPeriodsThird;
128 jakw 62
        cv::Mat patternI(1,1,CV_8U);
63
        patternI = computePhaseVector(screenCols, phase, pitch);
64
        patterns.push_back(patternI.t());
65
    }
4 jakw 66
 
67
}
68
 
128 jakw 69
cv::Mat AlgorithmPhaseShiftThreeFreq::getEncodingPattern(unsigned int depth){
4 jakw 70
    return patterns[depth];
71
}
72
 
245 jakw 73
void AlgorithmPhaseShiftThreeFreq::get3DPoints(const SMCalibrationParameters & calibration, const std::vector<cv::Mat>& frames0, const std::vector<cv::Mat>& frames1, std::vector<cv::Point3f>& Q, std::vector<cv::Vec3f>& color){
4 jakw 74
 
70 jakw 75
    assert(frames0.size() == N);
76
    assert(frames1.size() == N);
77
 
78
    int frameRows = frames0[0].rows;
79
    int frameCols = frames0[0].cols;
80
 
190 jakw 81
    float nPeriodsThird = 1 + 2*nPeriodsSecond - nPeriodsFirst;
82
 
83
 
179 jakw 84
    // Rectifying homographies (rotation+projections)
85
    cv::Size frameSize(frameCols, frameRows);
86
    cv::Mat R, T;
87
    // stereoRectify segfaults unless R is double precision
88
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
89
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
90
    cv::Mat R0, R1, P0, P1, QRect;
91
    cv::stereoRectify(calibration.K0, calibration.k0, calibration.K1, calibration.k1, frameSize, R, T, R0, R1, P0, P1, QRect, 0);
92
 
93
    // Interpolation maps (lens distortion and rectification)
94
    cv::Mat map0X, map0Y, map1X, map1Y;
95
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0, R0, P0, frameSize, CV_32F, map0X, map0Y);
96
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1, R1, P1, frameSize, CV_32F, map1X, map1Y);
97
 
98
 
99
    // Gray-scale and remap
100
    std::vector<cv::Mat> frames0Rect(N);
101
    std::vector<cv::Mat> frames1Rect(N);
167 jakw 102
    for(unsigned int i=0; i<N; i++){
179 jakw 103
        cv::Mat temp;
245 jakw 104
        cv::cvtColor(frames0[i], temp, CV_RGB2GRAY);
179 jakw 105
        cv::remap(temp, frames0Rect[i], map0X, map0Y, CV_INTER_LINEAR);
245 jakw 106
        cv::cvtColor(frames1[i], temp, CV_RGB2GRAY);
179 jakw 107
        cv::remap(temp, frames1Rect[i], map1X, map1Y, CV_INTER_LINEAR);
70 jakw 108
    }
109
 
110
    // Decode camera0
188 jakw 111
    std::vector<cv::Mat> frames0First(frames0Rect.begin()+2, frames0Rect.begin()+2+nStepsFirst);
112
    std::vector<cv::Mat> frames0Second(frames0Rect.begin()+2+nStepsFirst, frames0Rect.end()-nStepsThird);
113
    std::vector<cv::Mat> frames0Third(frames0Rect.end()-nStepsThird, frames0Rect.end());
129 jakw 114
 
188 jakw 115
    std::vector<cv::Mat> F0First = getDFTComponents(frames0First);
116
    cv::Mat up0First;
117
    cv::phase(F0First[2], -F0First[3], up0First);
118
    std::vector<cv::Mat> F0Second = getDFTComponents(frames0Second);
119
    cv::Mat up0Second;
120
    cv::phase(F0Second[2], -F0Second[3], up0Second);
121
    std::vector<cv::Mat> F0Third = getDFTComponents(frames0Third);
122
    cv::Mat up0Third;
123
    cv::phase(F0Third[2], -F0Third[3], up0Third);
128 jakw 124
 
190 jakw 125
    cv::Mat up0FS = up0Second - up0First;
192 jakw 126
    up0FS = cvtools::modulo(up0FS, 2.0*CV_PI);
182 jakw 127
 
190 jakw 128
    cv::Mat up0ST = up0Third - up0Second;
192 jakw 129
    up0ST = cvtools::modulo(up0ST, 2.0*CV_PI);
182 jakw 130
 
190 jakw 131
    cv::Mat up0FST = up0ST - up0FS;
192 jakw 132
    up0FST = cvtools::modulo(up0FST, 2.0*CV_PI);
182 jakw 133
 
190 jakw 134
    cv::Mat up0F = unwrapWithCue(up0First, up0FST, nPeriodsFirst);
135
    cv::Mat up0S = unwrapWithCue(up0Second, up0FST, nPeriodsSecond);
136
    cv::Mat up0T = unwrapWithCue(up0Third, up0FST, nPeriodsThird);
137
    cv::Mat up0Mean = 1.0/3.0 * (up0F + up0S + up0T);
138
    cv::Mat up0Range = cv::max(up0F, cv::max(up0S, up0T)) - cv::min(up0F, cv::min(up0S, up0T));
192 jakw 139
    cv::Mat up0 = up0Mean * screenCols/(2.0*CV_PI);
188 jakw 140
 
128 jakw 141
    cv::Mat amplitude0;
188 jakw 142
    cv::magnitude(F0First[2], -F0First[3], amplitude0);
70 jakw 143
 
144
    // Decode camera1
188 jakw 145
    std::vector<cv::Mat> frames1First(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsFirst);
146
    std::vector<cv::Mat> frames1Second(frames1Rect.begin()+2+nStepsFirst, frames1Rect.end()-nStepsThird);
147
    std::vector<cv::Mat> frames1Third(frames1Rect.end()-nStepsThird, frames1Rect.end());
129 jakw 148
 
188 jakw 149
    std::vector<cv::Mat> F1First = getDFTComponents(frames1First);
150
    cv::Mat up1First;
151
    cv::phase(F1First[2], -F1First[3], up1First);
152
    std::vector<cv::Mat> F1Second = getDFTComponents(frames1Second);
153
    cv::Mat up1Second;
154
    cv::phase(F1Second[2], -F1Second[3], up1Second);
155
    std::vector<cv::Mat> F1Third = getDFTComponents(frames1Third);
156
    cv::Mat up1Third;
157
    cv::phase(F1Third[2], -F1Third[3], up1Third);
128 jakw 158
 
190 jakw 159
    cv::Mat up1FS = up1Second - up1First;
192 jakw 160
    up1FS = cvtools::modulo(up1FS, 2.0*CV_PI);
182 jakw 161
 
190 jakw 162
    cv::Mat up1ST = up1Third - up1Second;
192 jakw 163
    up1ST = cvtools::modulo(up1ST, 2.0*CV_PI);
182 jakw 164
 
190 jakw 165
    cv::Mat up1FST = up1ST - up1FS;
192 jakw 166
    up1FST = cvtools::modulo(up1FST, 2.0*CV_PI);
182 jakw 167
 
190 jakw 168
    cv::Mat up1F = unwrapWithCue(up1First, up1FST, nPeriodsFirst);
169
    cv::Mat up1S = unwrapWithCue(up1Second, up1FST, nPeriodsSecond);
170
    cv::Mat up1T = unwrapWithCue(up1Third, up1FST, nPeriodsThird);
171
    cv::Mat up1Mean = 1.0/3.0 * (up1F + up1S + up1T);
172
    cv::Mat up1Range = cv::max(up1F, cv::max(up1S, up1T)) - cv::min(up1F, cv::min(up1S, up1T));
192 jakw 173
    cv::Mat up1 = up1Mean * screenCols/(2.0*CV_PI);
190 jakw 174
 
128 jakw 175
    cv::Mat amplitude1;
188 jakw 176
    cv::magnitude(F1First[2], -F1First[3], amplitude1);
70 jakw 177
 
185 jakw 178
    #ifdef QT_DEBUG
188 jakw 179
        cvtools::writeMat(up0First, "up0First.mat", "up0First");
180
        cvtools::writeMat(up0Second, "up0Second.mat", "up0Second");
181
        cvtools::writeMat(up0Third, "up0Third.mat", "up0Third");
190 jakw 182
        cvtools::writeMat(up0FS, "up0FS.mat", "up0FS");
183
        cvtools::writeMat(up0ST, "up0ST.mat", "up0ST");
184
        cvtools::writeMat(up0FST, "up0FST.mat", "up0FST");
185
        cvtools::writeMat(up0Mean, "up0Mean.mat", "up0Mean");
186
        cvtools::writeMat(up0Range, "up0Range.mat", "up0Range");
182 jakw 187
        cvtools::writeMat(up0, "up0.mat", "up0");
188
        cvtools::writeMat(up1, "up1.mat", "up1");
189
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
71 jakw 190
 
182 jakw 191
        cvtools::writeMat(amplitude0, "amplitude0.mat", "amplitude0");
192
        cvtools::writeMat(amplitude1, "amplitude1.mat", "amplitude1");
193
    #endif
70 jakw 194
 
245 jakw 195
    // color remap
179 jakw 196
    cv::Mat color0, color1;
245 jakw 197
    cv::remap(frames0[0], color0, map0X, map0Y, CV_INTER_LINEAR);
198
    cv::remap(frames1[0], color1, map1X, map1Y, CV_INTER_LINEAR);
187 jakw 199
 
185 jakw 200
    #ifdef QT_DEBUG
182 jakw 201
        cvtools::writeMat(color0, "color0.mat", "color0");
202
        cvtools::writeMat(color1, "color1.mat", "color1");
203
    #endif
70 jakw 204
 
205
    // Occlusion masks
179 jakw 206
    cv::Mat occlusion0, occlusion1;
207
    cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
245 jakw 208
    occlusion0 = (occlusion0 > 0.1) & (occlusion0 < 0.98);
179 jakw 209
    cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
245 jakw 210
    occlusion1 = (occlusion1 > 0.1) & (occlusion1 < 0.98);
70 jakw 211
 
190 jakw 212
    // Threshold on range
213
    occlusion0 = occlusion0 & (up0Range < 0.05);
214
    occlusion1 = occlusion1 & (up1Range < 0.05);
215
 
216
//    // Erode occlusion masks
217
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
218
//    cv::erode(occlusion0, occlusion0, strel);
219
//    cv::erode(occlusion1, occlusion1, strel);
220
 
245 jakw 221
    // Threshold on vertical gradient of phase
71 jakw 222
    cv::Mat edges0;
245 jakw 223
    cv::Sobel(up0, edges0, -1, 0, 1, 5);
224
    occlusion0 = occlusion0 & (abs(edges0) < 100);
71 jakw 225
    cv::Mat edges1;
245 jakw 226
    cv::Sobel(up1, edges1, -1, 0, 1, 5);
227
    occlusion1 = occlusion1 & (abs(edges1) < 100);
71 jakw 228
 
185 jakw 229
    #ifdef QT_DEBUG
182 jakw 230
        cvtools::writeMat(edges0, "edges0.mat", "edges0");
231
        cvtools::writeMat(edges1, "edges1.mat", "edges1");
232
    #endif
71 jakw 233
 
187 jakw 234
    #ifdef QT_DEBUG
235
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
236
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
237
    #endif
238
 
70 jakw 239
    // Match phase maps
240
    int frameRectRows = map0X.rows;
241
    int frameRectCols = map0X.cols;
242
 
243
    // camera0 against camera1
179 jakw 244
    std::vector<cv::Vec2f> q0, q1;
70 jakw 245
    for(int row=0; row<frameRectRows; row++){
246
        for(int col=0; col<frameRectCols; col++){
247
 
179 jakw 248
            if(!occlusion0.at<char>(row,col))
70 jakw 249
                continue;
250
 
179 jakw 251
            float up0i = up0.at<float>(row,col);
252
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 253
 
179 jakw 254
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 255
                    continue;
256
 
179 jakw 257
                float up1Left = up1.at<float>(row,col1);
258
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 259
 
189 jakw 260
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
70 jakw 261
 
262
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
263
 
179 jakw 264
                    q0.push_back(cv::Point2f(col, row));
265
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 266
 
267
                    break;
70 jakw 268
                }
269
            }
270
        }
271
    }
272
 
179 jakw 273
    int nMatches = q0.size();
70 jakw 274
 
275
    if(nMatches < 1){
276
        Q.resize(0);
277
        color.resize(0);
278
 
279
        return;
280
    }
281
 
282
    // Retrieve color information
283
    color.resize(nMatches);
284
    for(int i=0; i<nMatches; i++){
285
 
245 jakw 286
        cv::Vec3f c0 = color0.at<cv::Vec3f>(q0[i][1], q0[i][0]);
287
        cv::Vec3f c1 = color1.at<cv::Vec3f>(q1[i][1], q1[i][0]);
70 jakw 288
 
289
        color[i] = 0.5*c0 + 0.5*c1;
290
    }
291
 
236 jakw 292
    // Triangulate by means of disparity projection
293
    Q.resize(q0.size());
294
    cv::Matx44f QRectx = cv::Matx44f(QRect);
295
    cv::Matx33f R0invx = cv::Matx33f(cv::Mat(R0.t()));
70 jakw 296
 
236 jakw 297
    #pragma omp parallel for
298
    for(unsigned int i=0; i<q0.size(); i++){
299
        float disparity = q0[i][0]-q1[i][0];
300
        cv::Vec4f Qih = QRectx*cv::Vec4f(q0[i][0], q0[i][1], disparity, 1.0);
301
        float winv = float(1.0)/Qih[3];
302
        Q[i] = R0invx * cv::Point3f(Qih[0]*winv, Qih[1]*winv, Qih[2]*winv);
303
    }
70 jakw 304
 
4 jakw 305
}