root / trunk / tbeta / Windows / addons / ofxTBeta / Calibration / calibrationB.cpp @ 66

View | Annotate | Download (11 KB)

1
#include "calibrationB.h"
2
3
//set some default values
4
calibrationB::calibrationB()
5
{
6
        //Default values
7
        _camWidth = 320;
8
        _camHeight = 240;
9
}
10
11
//--------------------------------------------------------------
12
//        Load Settings from the config.xml file
13
//--------------------------------------------------------------
14
void calibrationB::loadXMLSettings(){
15
        
16
        bGoToNextStep = false;
17
18
        // Can this load via http?
19
        if( calibrationXML.loadFile("calibration.xml")){
20
                //WOOT!
21
                message = "Calibration Loaded!";
22
        }else{
23
                //FAIL!
24
                message = "No calibration Found...";
25
                // GENERATE DEFAULT XML DATA WHICH WILL BE SAVED INTO THE CONFIG
26
        }
27
28
        bool bboxRoot = true;
29
        bool screenRoot = true;
30
31
        bCalibrating = false;
32
        calibrationStep = 0;
33
34
        //Set grid and init everything that relates to teh grid.
35
36
        GRID_X                = calibrationXML.getValue("SCREEN:GRIDMESH:GRIDX", 50);
37
        GRID_Y                = calibrationXML.getValue("SCREEN:GRIDMESH:GRIDY", 50);
38
39
        setGrid(GRID_X, GRID_Y);
40
41
42
        //Bounding Box Points
43
        if(bboxRoot){
44
45
            vector2df ul(calibrationXML.getValue("SCREEN:BOUNDINGBOX:ulx", 0.000000),calibrationXML.getValue("SCREEN:BOUNDINGBOX:uly", 0.000000));
46
            vector2df lr(calibrationXML.getValue("SCREEN:BOUNDINGBOX:lrx", 1.000000),calibrationXML.getValue("SCREEN:BOUNDINGBOX:lry", 1.000000));
47
                rect2df boundingbox(ul, lr);
48
49
                setScreenBBox(boundingbox);
50
51
        }else{
52
                setScreenScale(1.0f);
53
        }
54
55
        //Calibration Points
56
        if(screenRoot)
57
        {
58
                //lets see how many <STROKE> </STROKE> tags there are in the xml file
59
                int numDragTags = calibrationXML.getNumTags("SCREEN:POINT");
60
61
                        printf("Points: %i \n", numDragTags);
62
63
                        //if there is at least one <POINT> tag we can read the list of points
64
                        if(numDragTags > 0){
65
66
                                //we push into the last POINT tag this temporarirly treats the tag as the document root.
67
                                calibrationXML.pushTag("SCREEN:POINT", numDragTags-1);
68
69
                                //we see how many points we have stored in <POINT> tags
70
                                int numPtTags = calibrationXML.getNumTags("POINT");
71
72
                        if(numPtTags > 0){
73
74
                                //We then read those x y values into our array
75
                                for(int i = 0; i < numPtTags; i++){
76
77
                                        //the last argument of getValue can be used to specify
78
                                        //which tag out of multiple tags you are refering to.
79
                                        int x = calibrationXML.getValue("POINT:X", 0.000000, i);
80
                                        int y = calibrationXML.getValue("POINT:Y", 0.000000, i);
81
82
                                        cameraPoints[i] = vector2df(x,y);
83
                                        printf("Calibration: %f, %f\n", cameraPoints[i].X, cameraPoints[i].Y);
84
85
                                        bscreenPoints = true;
86
                                        bcameraPoints = true;
87
                                }
88
                        }
89
                        calibrationXML.popTag(); //Set XML root back to highest level
90
                }
91
        }
92
        //End calibrationXML Calibration Settings
93
94
        //Set the camera calibated box.
95
        calculateBox();
96
        computeCameraToScreenMap();
97
}
98
99
100
/*****************************************************************************
101
 * Start of Calibration Methods
102
 *****************************************************************************/
103
104
//Bounding Box Size
105
void calibrationB::setScreenBBox(rect2df &box)
106
{
107
        screenBB = box;
108
        initScreenPoints();
109
}
110
111
//Compute a map of camera to screen coordinates
112
void calibrationB::computeCameraToScreenMap()
113
{
114
        cameraToScreenMap = new vector2df[_camWidth * _camHeight];
115
116
        int p = 0;
117
        for(int y = 0; y < _camHeight; y++)
118
        {
119
                for(int x = 0; x < _camWidth; x++)
120
                {
121
                        //cast to float
122
                        float transformedX = (float)x;
123
                        float transformedY = (float)y;
124
125
                        //convert camera to screenspace for all possible camera positions
126
                        cameraToScreenSpace(transformedX, transformedY);
127
                        //save these into a map of transformed camera to screenspace positions
128
                        cameraToScreenMap[p] = vector2df(transformedX, transformedY);
129
                        p++;
130
                }
131
        }
132
}
133
134
135
void calibrationB::setGrid(int x, int y)
136
{
137
        GRID_Y = y;
138
        GRID_X = x;
139
140
        GRID_POINTS = ((GRID_X+1) * (GRID_Y+1));
141
    GRID_INDICES = (GRID_X * GRID_Y * 3 * 2);
142
143
        screenPoints = new vector2df[GRID_POINTS];
144
        cameraPoints = new vector2df[GRID_POINTS];
145
        triangles    = new int[GRID_INDICES];
146
147
        initTriangles();
148
149
        if(bscreenPoints && bcameraPoints){
150
        initScreenPoints();
151
        initCameraPoints(_camWidth, _camHeight);
152
        }
153
}
154
155
void calibrationB::setCamRes(int camWidth = 320, int camHeight = 240)
156
{
157
        _camWidth = camWidth;
158
        _camHeight = camHeight;
159
}
160
161
void calibrationB::initTriangles(){
162
163
        int i,j;
164
        int t = 0;
165
166
        for(j=0; j<GRID_Y; j++)
167
        {
168
                for(i=0; i<GRID_X; i++)
169
                {
170
                        triangles[t+0] = (i+0) + ((j+0) * (GRID_X+1));
171
                        triangles[t+1] = (i+1) + ((j+0) * (GRID_X+1));
172
                        triangles[t+2] = (i+0) + ((j+1) * (GRID_X+1));
173
174
                        t += 3;
175
176
                        triangles[t+0] = (i+1) + ((j+0) * (GRID_X+1));
177
                        triangles[t+1] = (i+1) + ((j+1) * (GRID_X+1));
178
                        triangles[t+2] = (i+0) + ((j+1) * (GRID_X+1));
179
180
                        t += 3;
181
                }
182
        }
183
}
184
185
186
//Initialize Points
187
void calibrationB::initScreenPoints()
188
{
189
        int p = 0;
190
191
        int i,j;
192
193
        vector2df xd(screenBB.lowerRightCorner.X-screenBB.upperLeftCorner.X,0.0f);
194
        vector2df yd(0.0f, screenBB.lowerRightCorner.Y-screenBB.upperLeftCorner.Y);
195
196
        xd /= (float) GRID_X;
197
        yd /= (float) GRID_Y;
198
199
        for(j=0; j<=GRID_Y; j++)
200
        {
201
                for(i=0; i<=GRID_X; i++)
202
                {
203
                        screenPoints[p] = screenBB.upperLeftCorner + xd*i + yd*j;
204
                        //printf("(%d, %d) = (%f, %f)\n", i, j, screenPoints[p].X, screenPoints[p].Y);
205
                        p++;
206
                }
207
        }
208
}
209
210
void calibrationB::initCameraPoints(int camWidth, int camHeight)
211
{
212
        int p = 0;
213
214
        int i,j;
215
        for(j=0; j<=GRID_Y; j++)
216
        {
217
                for(i=0; i<=GRID_X; i++)
218
                {
219
                        cameraPoints[p] = vector2df((i * camWidth) / (float)GRID_X, (j * camHeight) / (float)GRID_Y);
220
                        p++;
221
                }
222
        }
223
}
224
225
void calibrationB::setScreenScale(float s)
226
{
227
        // legacy
228
        float offset = (1.0f - s)*0.5f;
229
        screenBB = rect2df(vector2df(offset,offset),vector2df(1.0f-offset,1.0f-offset));
230
        initScreenPoints();
231
}
232
233
float calibrationB::getScreenScale()
234
{
235
        // legacy, take the minimum scale value that fits inside the bounding box
236
        float minValL = MIN(screenBB.lowerRightCorner.X,screenBB.lowerRightCorner.Y);
237
        minValL = 1.0f - minValL;
238
        float minValU = MAX(screenBB.upperLeftCorner.X,screenBB.upperLeftCorner.Y);
239
        float minVal = MIN(minValL,minValU);
240
        return 1.0f - (2.0f * minVal);
241
}
242
243
void calibrationB::cameraToScreenPosition(float &x, float &y)
244
{
245
        //is this right to avoid boundingbox overflow? this overflow occurs due to new angle box
246
        if(y > _camHeight) y = _camHeight;
247
        if(y < 0) y = 0;
248
        if(x > _camWidth) x = _camWidth;
249
        if(x < 0) x = 0;
250
251
        int pos = (int)y * (int)_camWidth + (int)x;
252
253
        x = cameraToScreenMap[pos].X;
254
        y = cameraToScreenMap[pos].Y;
255
256
        return;
257
}
258
259
void calibrationB::transformDimension(float &width, float &height)
260
{
261
        //Transform width/height
262
    float halfX = width * 0.5f;
263
    float halfY = height * 0.5f;
264
265
        //Take all blobs as if they're from the center of calibrated region
266
        float centerX = ((maxBoxX - minBoxX)/2) + minBoxX;
267
        float centerY = ((maxBoxY - minBoxY)/2) + minBoxY;
268
269
        //Calculate x/y position of upperleft and lowerright x/y positions
270
    float ulX = centerX - halfX;
271
    float ulY = centerY - halfY;
272
    float lrX = centerX + halfX;
273
    float lrY = centerY + halfY;
274
275
        //Transform these x/y positions to screenspace
276
        cameraToScreenPosition(ulX, ulY);
277
        cameraToScreenPosition(lrX, lrY);
278
279
        //Calculate new height/width
280
        width = lrX - ulX;
281
        height = ulY - lrY;
282
}
283
284
void calibrationB::calculateBox()
285
{
286
        //reset variables
287
        maxBoxX = 0;
288
        minBoxX = _camWidth;
289
        maxBoxY = 0;
290
        minBoxY = _camHeight;
291
292
        //Calculate the max/min points based on cameraPoints
293
        for(int i = 0; i < GRID_POINTS; i++){
294
295
                if(cameraPoints[i].X > maxBoxX){
296
297
                        maxBoxX = cameraPoints[i].X;
298
                }
299
                else if(cameraPoints[i].X < minBoxX){
300
301
                        minBoxX = cameraPoints[i].X;
302
                }
303
                if(cameraPoints[i].Y > maxBoxY){
304
305
                        maxBoxY = cameraPoints[i].Y;
306
                }
307
                if(cameraPoints[i].Y < minBoxY){
308
309
                        minBoxY = cameraPoints[i].Y;
310
                }
311
        }
312
}
313
314
315
// Transforms a camera space coordinate into a screen space coord
316
void calibrationB::cameraToScreenSpace(float &x, float &y)
317
{
318
319
        vector2df pt(x, y);
320
321
        int t = findTriangleWithin(pt);
322
323
        if(t != -1)
324
        {
325
326
                vector2df A = cameraPoints[triangles[t+0]];
327
                vector2df B = cameraPoints[triangles[t+1]];
328
                vector2df C = cameraPoints[triangles[t+2]];
329
                float total_area = (A.X - B.X) * (A.Y - C.Y) - (A.Y - B.Y) * (A.X - C.X);
330
331
                // pt,B,C
332
                float area_A = (pt.X - B.X) * (pt.Y - C.Y) - (pt.Y - B.Y) * (pt.X - C.X);
333
334
                // A,pt,C
335
                float area_B = (A.X - pt.X) * (A.Y - C.Y) - (A.Y - pt.Y) * (A.X - C.X);
336
337
                float bary_A = area_A / total_area;
338
                float bary_B = area_B / total_area;
339
                float bary_C = 1.0f - bary_A - bary_B;        // bary_A + bary_B + bary_C = 1
340
341
                vector2df sA = screenPoints[triangles[t+0]];
342
                vector2df sB = screenPoints[triangles[t+1]];
343
                vector2df sC = screenPoints[triangles[t+2]];
344
345
                vector2df transformedPos;
346
347
                transformedPos = (sA*bary_A) + (sB*bary_B) + (sC*bary_C);
348
349
                x = transformedPos.X;
350
                y = transformedPos.Y;
351
                return;
352
        }
353
354
        x = 0;
355
        y = 0;
356
        // FIXME: what to do in the case that it's outside the mesh?
357
}
358
359
bool calibrationB::isPointInTriangle(vector2df p, vector2df a, vector2df b, vector2df c)
360
{
361
        if (vector2df::isOnSameSide(p,a, b,c) && vector2df::isOnSameSide(p,b, a,c) && vector2df::isOnSameSide(p, c, a, b))
362
                return true;
363
    else
364
                return false;
365
}
366
367
368
int calibrationB::findTriangleWithin(vector2df pt)
369
{
370
        int t;
371
372
        for(t=0; t<GRID_INDICES; t+=3)
373
        {
374
                if( isPointInTriangle(pt, cameraPoints[triangles[t]], cameraPoints[triangles[t+1]], cameraPoints[triangles[t+2]]) )
375
                {
376
                        return t;
377
                }
378
        }
379
380
        return -1;
381
}
382
383
384
void calibrationB::beginCalibration()
385
{
386
         bCalibrating = true;
387
         calibrationStep = 0;
388
}
389
390
391
void calibrationB::nextCalibrationStep()
392
{
393
        if(bCalibrating)
394
        {
395
                calibrationStep++;
396
397
                if(calibrationStep >= GRID_POINTS)
398
                {
399
                        bCalibrating = false;
400
                        calibrationStep = 0;
401
                        saveCalibration();
402
                        calculateBox();
403
                        computeCameraToScreenMap();
404
405
            saveCalibration();
406
                }
407
        }
408
}
409
410
void calibrationB::revertCalibrationStep()
411
{
412
        if(bCalibrating)
413
        {
414
                calibrationStep--;
415
                if(calibrationStep < 0)
416
                {
417
                        calibrationStep = 0;
418
                }
419
        }
420
}
421
422
//Save Calibration Points to file
423
void calibrationB::saveCalibration()
424
{
425
426
        // -------------------------------- SAVE STATE ON EXIT
427
428
        //lets see how many <STROKE> </STROKE> tags there are in the xml file
429
        int numDragTags = calibrationXML.getNumTags("SCREEN:POINT");
430
431
        //if there is at least one <POINT> tag we can read the list of points
432
        if(numDragTags > 0){
433
434
                //we push into the last POINT tag this temporarirly treats the tag as the document root.
435
                calibrationXML.pushTag("SCREEN:POINT", numDragTags-1);
436
437
                calibrationXML.clear();
438
439
                //Save the Grid Mesh X/Y
440
                calibrationXML.setValue("GRIDMESH:GRIDX", GRID_X);
441
            calibrationXML.setValue("GRIDMESH:GRIDY", GRID_Y);
442
443
                //Save the Bounding Box
444
                calibrationXML.setValue("BOUNDINGBOX:ulx", screenBB.upperLeftCorner.X);
445
                calibrationXML.setValue("BOUNDINGBOX:uly", screenBB.upperLeftCorner.Y);
446
                calibrationXML.setValue("BOUNDINGBOX:lrx", screenBB.lowerRightCorner.X);
447
                calibrationXML.setValue("BOUNDINGBOX:lry", screenBB.lowerRightCorner.Y);
448
449
                //Save all the Calibration Points
450
                if(GRID_POINTS > 0){
451
452
                        //We then read those x y values into our array
453
                        for(int i = 0; i < GRID_POINTS; i++){
454
455
                                //the last argument of getValue can be used to specify
456
                                //which tag out of multiple tags you are refering to.
457
                                calibrationXML.setValue("POINT:X", cameraPoints[i].X, i);
458
                                calibrationXML.setValue("POINT:Y", cameraPoints[i].Y, i);
459
                        }
460
                }
461
                calibrationXML.popTag(); //Set XML root back to highest level
462
        }
463
        calibrationXML.saveFile("calibration.xml");
464
}