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
// Gray Code Structured Light with horizontal and vertical encoding
3
//
200 jakw 4
// This implementation of Gray encoding uses horizontal and vertial stripes, which adds some encoding redundancy, but avoids interpolation effects from rectifying homographies.
182 jakw 5
//
6
 
103 jakw 7
#include "AlgorithmGrayCodeHorzVert.h"
95 jakw 8
#include <cmath>
96 jakw 9
#include <assert.h>
95 jakw 10
#include "cvtools.h"
182 jakw 11
#include "algorithmtools.h"
95 jakw 12
 
13
// Algorithm
103 jakw 14
AlgorithmGrayCodeHorzVert::AlgorithmGrayCodeHorzVert(unsigned int _screenCols, unsigned int _screenRows) : Algorithm(_screenCols, _screenRows){
95 jakw 15
 
232 jakw 16
    NbitsHorz = ceilf(log2f((float)screenCols));
17
    NbitsVert =  ceilf(log2f((float)screenRows));
95 jakw 18
    N = 2 + (NbitsHorz+NbitsVert)*2;
19
 
20
    // all on pattern
21
    cv::Mat allOn(1, screenCols, CV_8UC3, cv::Scalar::all(255));
22
    patterns.push_back(allOn);
23
 
24
    // all off pattern
25
    cv::Mat allOff(1, screenCols, CV_8UC3, cv::Scalar::all(0));
26
    patterns.push_back(allOff);
27
 
28
 
29
    // horizontally encoding patterns
30
    for(unsigned int p=0; p<NbitsHorz; p++){
31
        cv::Mat pattern(1, screenCols, CV_8UC3);
32
        cv::Mat patternInv(1, screenCols, CV_8UC3);
33
 
34
        for(unsigned int j=0; j<screenCols; j++){
35
 
36
            unsigned int jGray = binaryToGray(j);
37
            // Amplitude of channels
232 jakw 38
            int bit = (int)getBit(jGray, NbitsHorz-p);
95 jakw 39
            pattern.at<cv::Vec3b>(0,j) = cv::Vec3b(255.0*bit,255.0*bit,255.0*bit);
40
            int invBit = bit^1;
41
            patternInv.at<cv::Vec3b>(0,j) = cv::Vec3b(255.0*invBit,255.0*invBit,255.0*invBit);
42
        }
43
        patterns.push_back(pattern);
44
        patterns.push_back(patternInv);
45
    }
46
 
47
    // vertical encoding patterns
48
    for(unsigned int p=0; p<NbitsVert; p++){
49
        cv::Mat pattern(screenRows, 1, CV_8UC3);
50
        cv::Mat patternInv(screenRows, 1, CV_8UC3);
51
 
52
        for(unsigned int j=0; j<screenRows; j++){
53
 
54
            unsigned int jGray = binaryToGray(j);
55
            // Amplitude of channels
232 jakw 56
            int bit = (int)getBit(jGray, NbitsVert-p);
95 jakw 57
            pattern.at<cv::Vec3b>(j,0) = cv::Vec3b(255.0*bit,255.0*bit,255.0*bit);
58
            int invBit = bit^1;
59
            patternInv.at<cv::Vec3b>(j,0) = cv::Vec3b(255.0*invBit,255.0*invBit,255.0*invBit);
60
        }
61
        patterns.push_back(pattern);
62
        patterns.push_back(patternInv);
63
    }
64
 
65
}
66
 
103 jakw 67
cv::Mat AlgorithmGrayCodeHorzVert::getEncodingPattern(unsigned int depth){
95 jakw 68
    return patterns[depth];
69
}
70
 
71
 
107 jakw 72
typedef struct intersection{
73
    unsigned int row;
74
    unsigned int col;
109 jakw 75
    // 64 bit integer (long long)
107 jakw 76
    unsigned long id;
108 jakw 77
    intersection() : row(0), col(0), id(0){}
78
    intersection(unsigned int _row, unsigned int _col, unsigned long long _id) :
79
        row(_row), col(_col), id(_id){}
107 jakw 80
} intersection;
95 jakw 81
 
82
 
107 jakw 83
static bool sortingLarger(intersection i,intersection j){ return (i.id<j.id);}
84
static bool sortingEqual(intersection i,intersection j){ return (i.id==j.id);}
85
 
108 jakw 86
static void getIntersectionLabels(const cv::Mat& codeHorz, const cv::Mat& codeVert, const int NbitsHorz, const int NbitsVert, std::vector<intersection>& intersections){
107 jakw 87
 
96 jakw 88
    int nRows = codeHorz.rows;
89
    int nCols = codeHorz.cols;
95 jakw 90
 
96 jakw 91
    int labelHorz;
92
    int labelVert;
93
    int labelHorzRight;
94
    int labelVertBelow;
95 jakw 95
 
96 jakw 96
    // collect intersections
109 jakw 97
    for(int row=0; row<nRows-1; row++){
98
        for(int col=0; col<nCols-1; col++){
95 jakw 99
 
96 jakw 100
            labelHorz = codeHorz.at<int>(row, col);
101
            labelHorzRight = codeHorz.at<int>(row, col+1);
102
 
103
            labelVert = codeVert.at<int>(row, col);
104
            labelVertBelow = codeVert.at<int>(row+1, col);
105
 
106
            // labels need to be non-background, and differ in exactly one bit
107
            if(labelHorz != -1 && labelHorzRight != -1 &&
122 jakw 108
               (grayToBinary(labelHorzRight) == grayToBinary(labelHorz)+1) &&
96 jakw 109
               labelVert != -1 && labelVertBelow != -1 &&
122 jakw 110
               (grayToBinary(labelVertBelow) == grayToBinary(labelVert)+1)){
96 jakw 111
 
108 jakw 112
                // shift together labels to form unique intersection id
109 jakw 113
                unsigned long id = ((ulong)labelHorz << (NbitsHorz+2*NbitsVert)) + ((ulong)labelHorzRight << (2*NbitsVert)) +
114
                                   ((ulong)labelVert << NbitsVert) + (ulong)labelVertBelow;
108 jakw 115
 
116
                // store intersection
117
                intersections.push_back(intersection(row, col, id));
96 jakw 118
            }
95 jakw 119
        }
120
    }
121
    // sort
96 jakw 122
    std::sort(intersections.begin(), intersections.end(), sortingLarger);
95 jakw 123
 
124
    // remove duplicates
107 jakw 125
    std::vector<intersection>::iterator it;
96 jakw 126
    it = std::unique(intersections.begin(), intersections.end(), sortingEqual);
127
    intersections.resize(std::distance(intersections.begin(),it));
95 jakw 128
}
129
 
108 jakw 130
static void getSubpixelCoordinates(const std::vector<intersection>& matches, const std::vector<cv::Mat>& frames, const int NbitsHorz, const int NbitsVert, std::vector<cv::Point2f> &q){
131
 
132
    int nMatches = matches.size();
133
    q.resize(nMatches);
134
 
135
    // subpixel refinement finds the intersection of linear interpolants in the positive/negative pattern
136
    for(int i=0; i<nMatches; i++){
137
 
138
        // shift the labels back out from id
109 jakw 139
        int labelHorz = (matches[i].id >> (NbitsHorz+2*NbitsVert)) & ((1 << NbitsHorz) - 1);
140
        int labelHorzRight = (matches[i].id >> (2*NbitsVert)) & ((1 << NbitsHorz) - 1);
141
        int labelVert = (matches[i].id >> NbitsVert) & ((1 << NbitsVert) - 1);
142
        int labelVertBelow = matches[i].id  & ((1 << NbitsVert) - 1);
108 jakw 143
 
109 jakw 144
//        std::cout << "id: " << matches[i].id << std::endl;
145
//        std::cout << "labelHorz: " << labelHorz << std::endl;
146
//        std::cout << "labelHorzRight: " << labelHorzRight << std::endl;
147
//        std::cout << "labelVert: " << labelVert << std::endl;
148
//        std::cout << "labelVertBelow: " << labelVertBelow << std::endl;
149
 
108 jakw 150
        // determine the levels at which the edges exists
151
        int levelHorz = NbitsHorz - leastSignificantBitSet(labelHorz^labelHorzRight);
152
        int levelVert = NbitsVert - leastSignificantBitSet(labelVert^labelVertBelow);
153
 
154
        // interpolate horizontal coordinate
155
        float row = matches[i].row;
156
        float col = matches[i].col;
157
        float colRight = col+1;
158
 
245 jakw 159
        float posHorz = frames[2*levelHorz+2].at<float>(row, col);
160
        float negHorz = frames[2*levelHorz+3].at<float>(row, col);
161
        float posHorzRight = frames[2*levelHorz+2].at<float>(row, colRight);
162
        float negHorzRight = frames[2*levelHorz+3].at<float>(row, colRight);
108 jakw 163
 
164
        float x = col + (posHorz - negHorz)/(negHorzRight - negHorz - posHorzRight + posHorz);
165
 
166
        // interpolate vertical coordinate
167
        float rowBelow = row+1;
168
 
245 jakw 169
        float posVert = frames[2*NbitsHorz+2*levelVert+2].at<float>(row, col);
170
        float negVert = frames[2*NbitsHorz+2*levelVert+3].at<float>(row, col);
171
        float posVertBelow = frames[2*NbitsHorz+2*levelVert+2].at<float>(rowBelow, col);
172
        float negVertBelow = frames[2*NbitsHorz+2*levelVert+3].at<float>(rowBelow, col);
108 jakw 173
 
174
        float y = row + (posVert - negVert)/(negVertBelow - negVert - posVertBelow + posVert);
175
 
176
        // write into return vector
109 jakw 177
        q[i] = cv::Point2f(x, y);
108 jakw 178
 
179
    }
180
}
181
 
245 jakw 182
void AlgorithmGrayCodeHorzVert::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){
95 jakw 183
 
184
    assert(frames0.size() == N);
185
    assert(frames1.size() == N);
186
 
187
    int frameRows = frames0[0].rows;
188
    int frameCols = frames0[0].cols;
189
 
190
    // gray-scale
191
    std::vector<cv::Mat> frames0Gray(N);
192
    std::vector<cv::Mat> frames1Gray(N);
167 jakw 193
    for(unsigned int i=0; i<N; i++){
245 jakw 194
        cv::cvtColor(frames0[i], frames0Gray[i], CV_RGB2GRAY);
195
        cv::cvtColor(frames1[i], frames1Gray[i], CV_RGB2GRAY);
95 jakw 196
    }
197
 
198
    // colors
245 jakw 199
    cv::Mat color0 = frames0[0];
200
    cv::Mat color1 = frames1[0];
95 jakw 201
 
202
    // occlusion masks
203
    cv::Mat occlusion0, occlusion1;
245 jakw 204
    cv::subtract(frames0Gray[0], frames0Gray[1], occlusion0);
205
    occlusion0 = (occlusion0 > 0.1) & (occlusion0 < 0.98);
206
    //occlusion0.convertTo(occlusion0, CV_8UC1);
207
    cv::subtract(frames1Gray[0], frames1Gray[1], occlusion1);
208
    occlusion1 = (occlusion1 > 0.1) & (occlusion1 < 0.98);
209
    //occlusion1.convertTo(occlusion1, CV_8UC1);
95 jakw 210
 
195 jakw 211
//    // erode occlusion masks
212
//    cv::Mat strel = cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(3,3));
213
//    cv::erode(occlusion0, occlusion0, strel);
214
//    cv::erode(occlusion1, occlusion1, strel);
95 jakw 215
 
245 jakw 216
        #ifdef QT_DEBUG
217
            cvtools::writeMat(occlusion0, "occlusion0.mat", "occlusion0");
218
            cvtools::writeMat(occlusion1, "occlusion1.mat", "occlusion1");
219
        #endif
95 jakw 220
 
221
    // decode patterns
222
    cv::Mat code0Horz(frameRows, frameCols, CV_32S, cv::Scalar(0));
223
    cv::Mat code1Horz(frameRows, frameCols, CV_32S, cv::Scalar(0));
224
    cv::Mat code0Vert(frameRows, frameCols, CV_32S, cv::Scalar(0));
225
    cv::Mat code1Vert(frameRows, frameCols, CV_32S, cv::Scalar(0));
226
 
227
    // horizontal codes into gray code
167 jakw 228
    for(unsigned int i=0; i<NbitsHorz; i++){
95 jakw 229
        cv::Mat bit0;
120 jakw 230
        cv::compare(frames0Gray[i*2+2], frames0Gray[i*2+3], bit0, cv::CMP_GT);
95 jakw 231
        bit0.convertTo(bit0, CV_32S, 1.0/255.0);
96 jakw 232
        cv::add(code0Horz, bit0*twopowi(NbitsHorz-i-1), code0Horz, cv::Mat(), CV_32S);
95 jakw 233
 
234
        cv::Mat bit1;
120 jakw 235
        cv::compare(frames1Gray[i*2+2], frames1Gray[i*2+3], bit1, cv::CMP_GT);
95 jakw 236
        bit1.convertTo(bit1, CV_32S, 1.0/255.0);
96 jakw 237
        cv::add(code1Horz, bit1*twopowi(NbitsHorz-i-1), code1Horz, cv::Mat(), CV_32S);
95 jakw 238
    }
239
 
240
    // vertical codes into gray code
167 jakw 241
    for(unsigned int i=0; i<NbitsVert; i++){
95 jakw 242
        cv::Mat bit0;
120 jakw 243
        cv::compare(frames0Gray[i*2+2*NbitsHorz+2], frames0Gray[i*2+2*NbitsHorz+3], bit0, cv::CMP_GT);
95 jakw 244
        bit0.convertTo(bit0, CV_32S, 1.0/255.0);
96 jakw 245
        cv::add(code0Vert, bit0*twopowi(NbitsVert-i-1), code0Vert, cv::Mat(), CV_32S);
95 jakw 246
 
247
        cv::Mat bit1;
120 jakw 248
        cv::compare(frames1Gray[i*2+2*NbitsHorz+2], frames1Gray[i*2+2*NbitsHorz+3], bit1, cv::CMP_GT);
95 jakw 249
        bit1.convertTo(bit1, CV_32S, 1.0/255.0);
96 jakw 250
        cv::add(code1Vert, bit1*twopowi(NbitsVert-i-1), code1Vert, cv::Mat(), CV_32S);
95 jakw 251
    }
252
 
253
    // set occluded pixels to -1
254
    for(int r=0; r<frameRows; r++){
255
        for(int c=0; c<frameCols; c++){
256
            if(occlusion0.at<char>(r,c) == 0){
109 jakw 257
                code0Horz.at<int>(r,c) = -1;
258
                code0Vert.at<int>(r,c) = -1;
95 jakw 259
            }
260
            if(occlusion1.at<char>(r,c) == 0){
109 jakw 261
                code1Horz.at<int>(r,c) = -1;
262
                code1Vert.at<int>(r,c) = -1;
95 jakw 263
            }
264
        }
265
    }
266
 
245 jakw 267
    #ifdef QT_DEBUG
268
        cvtools::writeMat(code0Horz, "code0Horz.mat", "code0Horz");
269
        cvtools::writeMat(code1Horz, "code1Horz.mat", "code1Horz");
270
        cvtools::writeMat(code0Vert, "code0Vert.mat", "code0Vert");
271
        cvtools::writeMat(code1Vert, "code1Vert.mat", "code1Vert");
272
    #endif
109 jakw 273
 
274
    // get intersections
107 jakw 275
    std::vector<intersection> intersections0, intersections1;
96 jakw 276
    getIntersectionLabels(code0Horz, code0Vert, NbitsHorz, NbitsVert, intersections0);
277
    getIntersectionLabels(code1Horz, code1Vert, NbitsHorz, NbitsVert, intersections1);
95 jakw 278
 
96 jakw 279
    // match intersections
107 jakw 280
    std::vector<intersection> matches0, matches1;
167 jakw 281
    unsigned int i=0, j=0;
95 jakw 282
 
96 jakw 283
    while(i<intersections0.size() && j<intersections1.size()){
107 jakw 284
        if(intersections0[i].id == intersections1[j].id){
96 jakw 285
            matches0.push_back(intersections0[i]);
286
            matches1.push_back(intersections1[j]);
287
            i += 1;
288
            j += 1;
107 jakw 289
        } else if(intersections0[i].id < intersections1[j].id){
96 jakw 290
            i += 1;
107 jakw 291
        } else if(intersections0[i].id > intersections1[j].id){
96 jakw 292
            j += 1;
293
        }
294
    }
95 jakw 295
 
98 jakw 296
    int nMatches = matches0.size();
95 jakw 297
 
98 jakw 298
    if(nMatches < 1){
299
        Q.resize(0);
300
        color.resize(0);
301
 
302
        return;
303
    }
304
 
108 jakw 305
    std::vector<cv::Point2f> q0(nMatches), q1(nMatches);
98 jakw 306
 
107 jakw 307
//    for(int i=0; i<nMatches; i++){
109 jakw 308
//        q0[i] = cv::Point2f(matches0[i].col, matches0[i].row);
309
//        q1[i] = cv::Point2f(matches1[i].col, matches1[i].row);
107 jakw 310
//    }
98 jakw 311
 
108 jakw 312
    // subpixel refinement
109 jakw 313
    getSubpixelCoordinates(matches0, frames0Gray, NbitsHorz, NbitsVert, q0);
314
    getSubpixelCoordinates(matches1, frames1Gray, NbitsHorz, NbitsVert, q1);
95 jakw 315
 
108 jakw 316
    // retrieve color information (at subpixel coordinates)
96 jakw 317
    color.resize(nMatches);
318
    for(int i=0; i<nMatches; i++){
245 jakw 319
        cv::Vec3f c0 = color0.at<cv::Vec3f>(std::floor(q0[i].y), std::floor(q0[i].x));
320
        cv::Vec3f c1 = color1.at<cv::Vec3f>(std::floor(q1[i].y), std::floor(q1[i].x));
95 jakw 321
 
96 jakw 322
        color[i] = 0.5*c0 + 0.5*c1;
323
    }
95 jakw 324
 
114 jakw 325
    //cv::correctMatches(calibration.F, q0, q1, q0, q1);
120 jakw 326
    // correct for lens distortion
114 jakw 327
    cv::undistortPoints(q0, q0, calibration.K0, calibration.k0, cv::noArray(), calibration.K0);
328
    cv::undistortPoints(q1, q1, calibration.K1, calibration.k1, cv::noArray(), calibration.K1);
329
    cv::correctMatches(calibration.F, q0, q1, q0, q1);
330
 
236 jakw 331
    // Triangulate points
96 jakw 332
    cv::Mat P0(3, 4, CV_32F, cv::Scalar(0.0));
333
    cv::Mat(calibration.K0).copyTo(P0.colRange(0, 3));
95 jakw 334
 
96 jakw 335
    cv::Mat P1(3, 4, CV_32F), temp(3,4,CV_32F);
336
    cv::Mat(calibration.R1).copyTo(temp(cv::Range(0,3), cv::Range(0,3)));
337
    cv::Mat(calibration.T1).copyTo(temp(cv::Range(0,3), cv::Range(3,4)));
338
    P1 = cv::Mat(calibration.K1) * temp;
95 jakw 339
 
96 jakw 340
    cv::Mat QMatHomogenous, QMat;
341
    cv::triangulatePoints(P0, P1, q0, q1, QMatHomogenous);
95 jakw 342
 
96 jakw 343
    cvtools::convertMatFromHomogeneous(QMatHomogenous, QMat);
344
    cvtools::matToPoints3f(QMat, Q);
95 jakw 345
 
346
}