Subversion Repositories seema-scanner

Rev

Rev 190 | Rev 195 | 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);
219
    occlusion0 = occlusion0 & (abs(edges0) < 150);
71 jakw 220
 
190 jakw 221
    cv::Mat edges1;
222
    cv::Sobel(up1, edges1, -1, 1, 1, 5);
223
    occlusion1 = occlusion1 & (abs(edges1) < 150);
71 jakw 224
 
185 jakw 225
    #ifdef QT_DEBUG
226
        cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
182 jakw 227
        cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
228
    #endif
229
 
70 jakw 230
    // Match phase maps
231
 
232
    // camera0 against camera1
178 jakw 233
    std::vector<cv::Vec2f> q0, q1;
70 jakw 234
    for(int row=0; row<frameRectRows; row++){
235
        for(int col=0; col<frameRectCols; col++){
236
 
178 jakw 237
            if(!occlusion0.at<char>(row,col))
70 jakw 238
                continue;
239
 
178 jakw 240
            float up0i = up0.at<float>(row,col);
241
            for(int col1=0; col1<up1.cols-1; col1++){
70 jakw 242
 
178 jakw 243
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 244
                    continue;
245
 
178 jakw 246
                float up1Left = up1.at<float>(row,col1);
247
                float up1Right = up1.at<float>(row,col1+1);
70 jakw 248
 
190 jakw 249
                if((up1Left <= up0i) && (up0i <= up1Right) && (up0i-up1Left < 1.0) && (up1Right-up0i < 1.0) && (up1Right-up1Left > 0.1)){
70 jakw 250
 
251
                    float col1i = col1 + (up0i-up1Left)/(up1Right-up1Left);
252
 
178 jakw 253
                    q0.push_back(cv::Point2f(col, row));
254
                    q1.push_back(cv::Point2f(col1i, row));
71 jakw 255
 
256
                    break;
70 jakw 257
                }
258
            }
259
        }
260
    }
261
 
262
 
178 jakw 263
    int nMatches = q0.size();
74 jakw 264
 
70 jakw 265
    if(nMatches < 1){
266
        Q.resize(0);
267
        color.resize(0);
268
 
269
        return;
270
    }
271
 
272
    // Retrieve color information
273
    color.resize(nMatches);
274
    for(int i=0; i<nMatches; i++){
275
 
178 jakw 276
        cv::Vec3b c0 = color0.at<cv::Vec3b>(q0[i][1], q0[i][0]);
277
        cv::Vec3b c1 = color1.at<cv::Vec3b>(q1[i][1], q1[i][0]);
70 jakw 278
 
279
        color[i] = 0.5*c0 + 0.5*c1;
280
    }
281
 
282
    // Triangulate points
283
    cv::Mat QMatHomogenous, QMat;
178 jakw 284
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
70 jakw 285
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
286
 
287
    // Undo rectification
288
    cv::Mat R0Inv;
289
    cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
290
    QMat = R0Inv*QMat;
291
 
292
    cvtools::matToPoints3f(QMat, Q);
293
 
4 jakw 294
}