Subversion Repositories seema-scanner

Rev

Rev 231 | Rev 234 | 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
 
231 jakw 17
#include <omp.h>
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
 
233 - 64
 
65
struct StereoRectifyier {
66
    cv::Mat map0X, map0Y, map1X, map1Y;
67
    cv::Mat R0, R1, P0, P1, QRect;
68
};
69
static void getStereoRectifyier(const SMCalibrationParameters &calibration,
70
                                const cv::Size& frameSize,
71
                                StereoRectifyier& stereoRect);
72
static void determineAmplitudePhaseEnergy(std::vector<cv::Mat>& frames,
73
                                    cv::Mat& amplitude, cv::Mat& phase, cv::Mat& energy);
74
static void collectPhases(const cv::Mat& phasePrimary, const cv::Mat& phaseSecondary,
75
                          cv::Mat& phase);
76
static void matchPhaseMaps(const cv::Mat& occlusion0, const cv::Mat& occlusion1,
77
                           const cv::Mat& phase0, const cv::Mat& phase1,
78
                           std::vector<cv::Vec2f>& q0, std::vector<cv::Vec2f>& q1);
79
static void triangulate(const StereoRectifyier& stereoRect,
80
                        const std::vector<cv::Vec2f>& q0,
81
                        const std::vector<cv::Vec2f>& q1,
82
                        std::vector<cv::Point3f>& Q);
83
 
84
 
207 flgw 85
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 86
 
70 jakw 87
    assert(frames0.size() == N);
88
    assert(frames1.size() == N);
89
 
233 - 90
    StereoRectifyier stereoRect;
91
    getStereoRectifyier(calibration, cv::Size(frames0[0].cols, frames0[0].rows), stereoRect);
231 jakw 92
 
233 - 93
    // // Erode occlusion masks
94
    // cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5,5));
95
 
96
    cv::Mat up0, up1;
97
    cv::Mat occlusion0, occlusion1;
98
    cv::Mat color0, color1;
99
 
100
    #pragma omp parallel sections
231 jakw 101
    {
233 - 102
        #pragma omp section
103
        {
70 jakw 104
 
233 - 105
            // Gray-scale and remap/rectify
106
            std::vector<cv::Mat> frames0Rect(N);
178 jakw 107
 
233 - 108
            for(unsigned int i=0; i<N; i++){
109
                cv::Mat temp;
110
                cv::cvtColor(frames0[i], temp, CV_BayerBG2GRAY);
111
                cv::remap(temp, frames0Rect[i], stereoRect.map0X, stereoRect.map0Y, CV_INTER_LINEAR);
112
            }
207 flgw 113
 
233 - 114
            // Occlusion masks
115
            cv::subtract(frames0Rect[0], frames0Rect[1], occlusion0);
116
            occlusion0 = (occlusion0 > 25) & (occlusion0 < 250);
182 jakw 117
 
233 - 118
            // Decode camera0
119
            std::vector<cv::Mat> frames0Primary(frames0Rect.begin()+2, frames0Rect.begin()+2+nStepsPrimary);
120
            std::vector<cv::Mat> frames0Secondary(frames0Rect.begin()+2+nStepsPrimary, frames0Rect.end());
70 jakw 121
 
233 - 122
            frames0Rect.clear();
182 jakw 123
 
233 - 124
            cv::Mat amplitude0Primary, amplitude0Secondary;
125
            cv::Mat up0Primary, up0Secondary;
126
            cv::Mat energy0Primary, energy0Secondary;
127
            determineAmplitudePhaseEnergy(frames0Primary,
128
                                          amplitude0Primary, up0Primary, energy0Primary);
129
            determineAmplitudePhaseEnergy(frames0Secondary,
130
                                          amplitude0Secondary, up0Secondary, energy0Secondary);
207 flgw 131
 
233 - 132
            collectPhases(up0Primary, up0Secondary, up0);
231 jakw 133
 
233 - 134
            // Threshold on energy at primary frequency
135
            occlusion0 = occlusion0 & (amplitude0Primary > 5.0*nStepsPrimary);
136
            // Threshold on energy ratios
137
            occlusion0 = occlusion0 & (amplitude0Primary > 0.25*energy0Primary);
138
            occlusion0 = occlusion0 & (amplitude0Secondary > 0.25*energy0Secondary);
231 jakw 139
 
233 - 140
            // // Erode occlusion masks
141
            // cv::erode(occlusion0, occlusion0, strel);
231 jakw 142
 
233 - 143
            // Threshold on gradient of phase
144
            cv::Mat edges0;
145
            cv::Sobel(up0, edges0, -1, 1, 1, 5);
146
            occlusion0 = occlusion0 & (abs(edges0) < 10);
182 jakw 147
 
233 - 148
            #ifdef SM_DEBUG
149
                cvtools::writeMat(up0Primary, "up0Primary.mat", "up0Primary");
150
                cvtools::writeMat(up0Secondary, "up0Secondary.mat", "up0Secondary");
151
                cvtools::writeMat(up0, "up0.mat", "up0");
152
                cvtools::writeMat(amplitude0Primary, "amplitude0Primary.mat", "amplitude0Primary");
153
                cvtools::writeMat(amplitude0Secondary, "amplitude0Secondary.mat", "amplitude0Secondary");
154
                cvtools::writeMat(energy0Primary, "energy0Primary.mat", "energy0Primary");
155
                cvtools::writeMat(energy0Secondary, "energy0Secondary.mat", "energy0Secondary");
156
                cvtools::writeMat(edges0, "edges0.mat", "edges0");
157
                cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
158
            #endif
182 jakw 159
 
233 - 160
        }
161
        #pragma omp section
162
        {
70 jakw 163
 
233 - 164
            // Gray-scale and remap
165
            std::vector<cv::Mat> frames1Rect(N);
200 jakw 166
 
233 - 167
            for(unsigned int i=0; i<N; i++){
168
                cv::Mat temp;
169
                cv::cvtColor(frames1[i], temp, CV_BayerBG2GRAY);
170
                cv::remap(temp, frames1Rect[i], stereoRect.map1X, stereoRect.map1Y, CV_INTER_LINEAR);
171
            }
182 jakw 172
 
233 - 173
            // Occlusion masks
174
            cv::subtract(frames1Rect[0], frames1Rect[1], occlusion1);
175
            occlusion1 = (occlusion1 > 25) & (occlusion1 < 250);
176
 
177
            // Decode camera1
178
            std::vector<cv::Mat> frames1Primary(frames1Rect.begin()+2, frames1Rect.begin()+2+nStepsPrimary);
179
            std::vector<cv::Mat> frames1Secondary(frames1Rect.begin()+2+nStepsPrimary, frames1Rect.end());
180
 
181
            frames1Rect.clear();
182
 
183
            cv::Mat amplitude1Primary, amplitude1Secondary;
184
            cv::Mat up1Primary, up1Secondary;
185
            cv::Mat energy1Primary, energy1Secondary;
186
            determineAmplitudePhaseEnergy(frames1Primary,
187
                                          amplitude1Primary, up1Primary, energy1Primary);
188
            determineAmplitudePhaseEnergy(frames1Secondary,
189
                                          amplitude1Secondary, up1Secondary, energy1Secondary);
190
 
191
            collectPhases(up1Primary, up1Secondary, up1);
192
 
193
            // Threshold on energy at primary frequency
194
            occlusion1 = occlusion1 & (amplitude1Primary > 5.0*nStepsPrimary);
195
            // Threshold on energy ratios
196
            occlusion1 = occlusion1 & (amplitude1Primary > 0.25*energy1Primary);
197
            occlusion1 = occlusion1 & (amplitude1Secondary > 0.25*energy1Secondary);
198
 
199
            // // Erode occlusion masks
200
            // cv::erode(occlusion1, occlusion1, strel);
201
 
202
 
203
            // Threshold on gradient of phase
204
            cv::Mat edges1;
205
            cv::Sobel(up1, edges1, -1, 1, 1, 5);
206
            occlusion1 = occlusion1 & (abs(edges1) < 10);
207
 
208
            #ifdef SM_DEBUG
209
                cvtools::writeMat(up1Primary, "up1Primary.mat", "up1Primary");
210
                cvtools::writeMat(up1Secondary, "up1Secondary.mat", "up1Secondary");
211
                cvtools::writeMat(up1, "up1.mat", "up1");
212
                cvtools::writeMat(amplitude1Primary, "amplitude1Primary.mat", "amplitude1Primary");
213
                cvtools::writeMat(amplitude1Secondary, "amplitude1Secondary.mat", "amplitude1Secondary");
214
                cvtools::writeMat(energy1Primary, "energy1Primary.mat", "energy1Primary");
215
                cvtools::writeMat(energy1Secondary, "energy1Secondary.mat", "energy1Secondary");
216
                cvtools::writeMat(edges1, "edges1.mat", "edges1");
217
                cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
218
            #endif
219
 
220
        }
182 jakw 221
    }
222
 
207 flgw 223
 
233 - 224
    // Match phase maps
185 jakw 225
 
233 - 226
    // camera0 against camera1
227
    std::vector<cv::Vec2f> q0, q1;
228
    matchPhaseMaps(occlusion0, occlusion1, up0, up1, q0, q1);
231 jakw 229
 
233 - 230
    size_t nMatches = q0.size();
231
 
232
    if(nMatches < 1){
233
        Q.resize(0);
234
        color.resize(0);
235
 
236
        return;
231 jakw 237
    }
207 flgw 238
    {
233 - 239
        // color debayer and remap/rectify
182 jakw 240
 
233 - 241
        cv::cvtColor(frames1[0], color1, CV_BayerBG2RGB);
242
        cv::remap(color1, color1, stereoRect.map1X, stereoRect.map1Y, CV_INTER_LINEAR);
207 flgw 243
 
233 - 244
        #ifdef SM_DEBUG
245
            cvtools::writeMat(color0, "color0.mat", "color0");
246
            cvtools::writeMat(color1, "color1.mat", "color1");
247
        #endif
248
 
249
        // Retrieve color information
250
        color.resize(nMatches);
251
        for(unsigned int i=0; i<nMatches; i++){
252
 
253
            cv::Vec3b c0 = color0.at<cv::Vec3b>(int(q0[i][1]), int(q0[i][0]));
254
            cv::Vec3b c1 = color1.at<cv::Vec3b>(int(q1[i][1]), int(q1[i][0]));
255
 
256
            color[i] = 0.5*c0 + 0.5*c1;
257
        }
231 jakw 258
    }
207 flgw 259
 
233 - 260
    // Triangulate points
261
    triangulate(stereoRect, q0, q1, Q);
207 flgw 262
 
233 - 263
}
207 flgw 264
 
233 - 265
void getStereoRectifyier(const SMCalibrationParameters &calibration, const cv::Size& frameSize, StereoRectifyier& stereoRect){
231 jakw 266
 
233 - 267
    // cv::stereoRectify segfaults unless R is double precision
268
    cv::Mat R, T;
269
    cv::Mat(calibration.R1).convertTo(R, CV_64F);
270
    cv::Mat(calibration.T1).convertTo(T, CV_64F);
182 jakw 271
 
233 - 272
    cv::stereoRectify(calibration.K0, calibration.k0,
273
                      calibration.K1, calibration.k1,
274
                      frameSize, R, T,
275
                      stereoRect.R0, stereoRect.R1,
276
                      stereoRect.P0, stereoRect.P1,
277
                      stereoRect.QRect, 0);
182 jakw 278
 
233 - 279
    // Interpolation maps (lens distortion and rectification)
280
    cv::initUndistortRectifyMap(calibration.K0, calibration.k0,
281
                                stereoRect.R0, stereoRect.P0,
282
                                frameSize, CV_32F,
283
                                stereoRect.map0X, stereoRect.map0Y);
284
    cv::initUndistortRectifyMap(calibration.K1, calibration.k1,
285
                                stereoRect.R1, stereoRect.P1,
286
                                frameSize, CV_32F,
287
                                stereoRect.map1X, stereoRect.map1Y);
288
}
70 jakw 289
 
233 - 290
void determineAmplitudePhaseEnergy(std::vector<cv::Mat>& frames,
291
                                   cv::Mat& amplitude, cv::Mat& phase, cv::Mat& energy) {
292
 
293
    std::vector<cv::Mat> fourier = getDFTComponents(frames);
294
 
295
    cv::phase(fourier[2], -fourier[3], phase);
296
 
200 jakw 297
    // Signal energy at unit frequency
233 - 298
    cv::magnitude(fourier[2], -fourier[3], amplitude);
200 jakw 299
 
182 jakw 300
    // Collected signal energy at higher frequencies
233 - 301
    energy = cv::Mat(phase.rows, phase.cols, CV_32F, cv::Scalar(0.0));
182 jakw 302
 
233 - 303
    for(unsigned int i=0; i<frames.size()-1; i++){
182 jakw 304
        cv::Mat magnitude;
233 - 305
        cv::magnitude(fourier[i*2 + 2], fourier[i*2 + 3], magnitude);
306
        cv::add(energy, magnitude, energy, cv::noArray(), CV_32F);
182 jakw 307
    }
308
 
233 - 309
    frames.clear();
310
}
70 jakw 311
 
233 - 312
void collectPhases(const cv::Mat& phasePrimary, const cv::Mat& phaseSecondary,
313
                   cv::Mat& phase) {
314
    cv::Mat phaseEquivalent = phaseSecondary - phasePrimary;
315
    phaseEquivalent = cvtools::modulo(phaseEquivalent, 2.0*CV_PI);
316
    phase = unwrapWithCue(phasePrimary, phaseEquivalent, nPeriodsPrimary);
317
    phase *= phasePrimary.cols/(2.0*CV_PI);
318
}
207 flgw 319
 
231 jakw 320
 
233 - 321
void matchPhaseMaps(const cv::Mat& occlusion0, const cv::Mat& occlusion1,
322
                    const cv::Mat& phase0, const cv::Mat& phase1,
323
                    std::vector<cv::Vec2f>& q0, std::vector<cv::Vec2f>& q1) {
231 jakw 324
 
325
    #pragma omp parallel for
233 - 326
    for(int row=0; row<occlusion0.rows; row++){
327
        for(int col=0; col<occlusion0.cols; col++){
70 jakw 328
 
178 jakw 329
            if(!occlusion0.at<char>(row,col))
70 jakw 330
                continue;
331
 
233 - 332
            float phase0i = phase0.at<float>(row,col);
333
            for(int col1=0; col1<phase1.cols-1; col1++){
70 jakw 334
 
178 jakw 335
                if(!occlusion1.at<char>(row,col1) || !occlusion1.at<char>(row,col1+1))
70 jakw 336
                    continue;
337
 
233 - 338
                float phase1Left = phase1.at<float>(row,col1);
339
                float phase1Right = phase1.at<float>(row,col1+1);
70 jakw 340
 
233 - 341
                bool match = (phase1Left <= phase0i)
342
                              && (phase0i <= phase1Right)
343
                              && (phase0i-phase1Left < 1.0)
344
                              && (phase1Right-phase0i < 1.0)
345
                              && (phase1Right-phase1Left > 0.1);
70 jakw 346
 
233 - 347
                if(match){
70 jakw 348
 
233 - 349
                    float col1i = col1 + (phase0i-phase1Left)/(phase1Right-phase1Left);
350
 
231 jakw 351
                    #pragma omp critical
352
                    {
178 jakw 353
                    q0.push_back(cv::Point2f(col, row));
354
                    q1.push_back(cv::Point2f(col1i, row));
231 jakw 355
                    }
71 jakw 356
                    break;
70 jakw 357
                }
358
            }
359
        }
360
    }
361
 
207 flgw 362
}
70 jakw 363
 
233 - 364
void triangulate(const StereoRectifyier& stereoRect,
365
                 const std::vector<cv::Vec2f>& q0,
366
                 const std::vector<cv::Vec2f>& q1,
367
                 std::vector<cv::Point3f>& Q) {
70 jakw 368
 
233 - 369
    // cv::Mat QMatHomogenous, QMat;
370
    // cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
371
    // cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
70 jakw 372
 
233 - 373
    // // Undo rectification
374
    // cv::Mat R0Inv;
375
    // cv::Mat(R0.t()).convertTo(R0Inv, CV_32F);
376
    // QMat = R0Inv*QMat;
230 jakw 377
 
233 - 378
    // cvtools::matToPoints3f(QMat, Q);
231 jakw 379
 
380
 
381
    // Triangulate by means of disparity projection
382
    Q.resize(q0.size());
233 - 383
    cv::Matx44f QRectx = cv::Matx44f(stereoRect.QRect);
384
    cv::Matx33f R0invx = cv::Matx33f(cv::Mat(stereoRect.R0.t()));
231 jakw 385
 
386
    #pragma omp parallel for
233 - 387
    for(unsigned int i=0; i < q0.size(); i++){
388
        float disparity = q0[i][0] - q1[i][0];
231 jakw 389
        cv::Vec4f Qih = QRectx*cv::Vec4f(q0[i][0], q0[i][1], disparity, 1.0);
233 - 390
        float winv = float(1.0) / Qih[3];
231 jakw 391
        Q[i] = R0invx * cv::Point3f(Qih[0]*winv, Qih[1]*winv, Qih[2]*winv);
392
    }
4 jakw 393
}