Subversion Repositories seema-scanner

Rev

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