Subversion Repositories seema-scanner

Rev

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