Преглед изворни кода

Introduce a new PnP method

customisations
alemart пре 6 месеци
родитељ
комит
f6bdba3d6f

+ 1768
- 0
src/geometry/pnp.ts
Разлика између датотеке није приказан због своје велике величине
Прегледај датотеку


+ 88
- 0
src/trackers/image-tracker/image-tracker-utils.ts Прегледај датотеку

@@ -32,6 +32,7 @@ import { ReferenceImageWithMedia } from './reference-image';
32 32
 import { Utils } from '../../utils/utils';
33 33
 import { IllegalOperationError, IllegalArgumentError, NumericalError } from '../../utils/errors';
34 34
 import { NIS_SIZE, TRACK_GRID_GRANULARITY } from './settings';
35
+import { find6DoFHomography, solvePlanarPnPRansacOptions } from '../../geometry/pnp';
35 36
 
36 37
 /*
37 38
 
@@ -227,6 +228,93 @@ export class ImageTrackerUtils
227 228
 
228 229
     /**
229 230
      * Given n > 0 pairs of keypoints in NDC as a 2 x 2n [ src | dest ] matrix,
231
+     * find a 6 DoF perspective warp (homography) from src to dest in NDC
232
+     * @param cameraIntrinsics 3x3 camera intrinsics
233
+     * @param points compiled pairs of keypoints in NDC
234
+     * @param options to be passed to pnp
235
+     * @returns a pair [ 3x3 transformation matrix, quality score ]
236
+     */
237
+    static find6DoFHomographyNDC(cameraIntrinsics: SpeedyMatrix, points: SpeedyMatrix, options: solvePlanarPnPRansacOptions): SpeedyPromise<[SpeedyMatrix,number]>
238
+    {
239
+        // too few data points?
240
+        const n = points.columns / 2;
241
+        if(n < 4) {
242
+            return Speedy.Promise.reject(
243
+                new IllegalArgumentError(`Too few data points to compute a perspective warp`)
244
+            );
245
+        }
246
+
247
+        // compute a homography
248
+        const src = points.block(0, 1, 0, n-1);
249
+        const dest = points.block(0, 1, n, 2*n-1);
250
+        const homography = find6DoFHomography(src, dest, cameraIntrinsics, options);
251
+        //console.log('homography',homography.toString(), src.toString(), dest.toString());
252
+
253
+        // quit without refinement (test)
254
+        // we use a coarse estimate of the camera intrinsics
255
+        //return Speedy.Promise.resolve([homography, 0]);
256
+
257
+        const mask = Speedy.Matrix.Zeros(1, n);
258
+        const intermediate = Speedy.Matrix.Zeros(2, n);
259
+
260
+        // refine the result of find6DoFHomography() with DLT + RANSAC
261
+        return Speedy.Matrix.applyPerspectiveTransform(intermediate, src, homography)
262
+        .then(intermediate =>
263
+            Speedy.Matrix.findHomography(
264
+                Speedy.Matrix.Zeros(3),
265
+                intermediate,
266
+                dest,
267
+                {
268
+                    method: 'pransac',
269
+                    numberOfHypotheses: 512, // XXX we can reduce this number without compromising quality
270
+                    bundleSize: 128, // maybe make it a parameter in case we need an extra performance boost?
271
+                    reprojectionError: options.reprojectionError,
272
+                    mask,
273
+                }
274
+            )
275
+        )
276
+        .then(adjustment => adjustment.setTo(adjustment.times(homography)))
277
+        .then(newHomography => {
278
+
279
+            // count inliers
280
+            let m = 0;
281
+            const inliers = mask.read();
282
+            for(let i = 0; i < n; i++)
283
+                m += inliers[i];
284
+
285
+            /*
286
+            // count and collect inliers
287
+            let m = 0;
288
+            const _mask = mask.read(), _src = src.read(), _dest = dest.read();
289
+            const _isrc = new Array<number>(2*n), _idest = new Array<number>(2*n);
290
+            for(let i = 0; i < n; i++) {
291
+                if(_mask[i]) {
292
+                    const j = m++;
293
+                    _isrc[2*j] = _src[2*i];
294
+                    _isrc[2*j+1] = _src[2*i+1];
295
+                    _idest[2*j] = _dest[2*i];
296
+                    _idest[2*j+1] = _dest[2*i+1];
297
+                }
298
+            }
299
+            _isrc.length = _idest.length = 2*m;
300
+
301
+            // refine homography
302
+            if(m > 0) {
303
+                const isrc = Speedy.Matrix(2, m, _isrc);
304
+                const idest = Speedy.Matrix(2, m, _idest);
305
+                newHomography = refineHomography(newHomography, isrc, idest);
306
+            }
307
+            */
308
+
309
+            // done!
310
+            const score = m / n;
311
+            return [newHomography, score];
312
+
313
+        });
314
+    }
315
+
316
+    /**
317
+     * Given n > 0 pairs of keypoints in NDC as a 2 x 2n [ src | dest ] matrix,
230 318
      * find a perspective warp (homography) from src to dest in NDC
231 319
      * @param points compiled pairs of keypoints in NDC
232 320
      * @param options to be passed to speedy-vision

+ 1
- 1
src/trackers/image-tracker/settings.ts Прегледај датотеку

@@ -138,7 +138,7 @@ export const TRACK_RANSAC_REPROJECTIONERROR_NDC = TRACK_RANSAC_REPROJECTIONERROR
138 138
 export const TRACK_GRID_GRANULARITY = 10; //20; // the value of N
139 139
 
140 140
 /** Used to identify the best maches */
141
-export const TRACK_MATCH_RATIO = 0.75; // usually a value in [0.6, 0.8] - low values => strict tracking
141
+export const TRACK_MATCH_RATIO = 0.7; // usually a value in [0.6, 0.8] - low values => strict tracking
142 142
 
143 143
 /** Number of consecutive frames in which we tolerate a  "target lost" situation */
144 144
 export const TRACK_LOST_TOLERANCE = 15;

+ 54
- 8
src/trackers/image-tracker/states/tracking.ts Прегледај датотеку

@@ -67,6 +67,9 @@ const USE_TURBO = true;
67 67
 /** Number of PBOs; meaningful only when using turbo */
68 68
 const NUMBER_OF_PBOS = 2;
69 69
 
70
+/** Motion model */
71
+const NO_MOTION = Speedy.Matrix.Eye(3);
72
+
70 73
 
71 74
 
72 75
 /**
@@ -298,22 +301,25 @@ export class ImageTrackerTrackingState extends ImageTrackerState
298 301
             // find motion models
299 302
             const points = ImageTrackerUtils.compilePairsOfKeypointsNDC(pairs);
300 303
             return Speedy.Promise.all<SpeedyMatrixExpr>([
301
-                this._findAffineMotionNDC(points),
302
-                this._findPerspectiveMotionNDC(points)
304
+                //this._findAffineMotionNDC(points),
305
+                //this._findPerspectiveMotionNDC(points),
306
+                this._find6DoFPerspectiveMotionNDC(points),
307
+                Speedy.Promise.resolve(NO_MOTION),
303 308
             ]);
304 309
 
305 310
         })
306
-        .then(([affineMotion, perspectiveMotion]) => {
311
+        .then(([warpMotion, poseMotion]) => {
307 312
 
308 313
             const lowPower = (Settings.powerPreference == 'low-power');
309 314
             const delay = NUMBER_OF_PBOS * (!lowPower ? 2 : 1);
310 315
 
311 316
             // update warp homography
312 317
             if(!USE_TURBO || this._counter % delay == 1) // skip the first frame (PBOs)
313
-                this._warpHomography.setToSync(affineMotion.times(this._warpHomography));
318
+                this._warpHomography.setToSync(warpMotion.times(this._warpHomography));
314 319
 
315 320
             // update pose homography
316
-            this._poseHomography.setToSync(perspectiveMotion.times(this._warpHomography));
321
+            //poseMotion = warpMotion; // commented: reduce jitter, increase delay
322
+            this._poseHomography.setToSync(poseMotion.times(this._warpHomography));
317 323
             if(Number.isNaN(this._poseHomography.at(0,0)))
318 324
                 throw new NumericalError('Bad homography'); // normalize? 1 / h33
319 325
 
@@ -324,8 +330,8 @@ export class ImageTrackerTrackingState extends ImageTrackerState
324 330
             // test
325 331
             console.log("POSE ", this._poseHomography.toString());
326 332
             console.log("WARP ", this._warpHomography.toString());
327
-            console.log("AMOT ", Speedy.Matrix(affineMotion).toString());
328
-            console.log("PMOT ", Speedy.Matrix(perspectiveMotion).toString());
333
+            console.log("AMOT ", Speedy.Matrix(warpMotion).toString());
334
+            console.log("PMOT ", Speedy.Matrix(poseMotion).toString());
329 335
             */
330 336
 
331 337
             // We transform the keypoints of the reference image to NDC as a
@@ -455,6 +461,8 @@ export class ImageTrackerTrackingState extends ImageTrackerState
455 461
 
456 462
         Note: work with a 6 DoF perspective transform instead of 8.
457 463
 
464
+        Edit: now we have find6DoFHomography()
465
+
458 466
         */
459 467
 
460 468
         return ImageTrackerUtils.findAffineWarpNDC(points, {
@@ -498,7 +506,8 @@ export class ImageTrackerTrackingState extends ImageTrackerState
498 506
             numberOfHypotheses: 512*2,
499 507
             bundleSize: 128,//128*4,
500 508
             mask: undefined // score is not needed
501
-        }).then(([ warp, score ]) => {
509
+        })
510
+        .then(([ warp, score ]) => {
502 511
 
503 512
             const scale = TRACK_RECTIFIED_SCALE;
504 513
             const aspectRatio = ImageTrackerUtils.bestFitAspectRatioNDC(this.screenSize, this._referenceImage!);
@@ -520,6 +529,43 @@ export class ImageTrackerTrackingState extends ImageTrackerState
520 529
     }
521 530
 
522 531
     /**
532
+     * Find a 6 DoF perspective motion model in NDC between pairs of keypoints in NDC
533
+     * given as a 2 x 2n [ src | dest ] matrix
534
+     * @param points compiled pairs of keypoints in NDC
535
+     * @returns a promise that resolves to a 3x3 warp in NDC that maps source to destination
536
+     */
537
+    private _find6DoFPerspectiveMotionNDC(points: SpeedyMatrix): SpeedyPromise<SpeedyMatrixExpr>
538
+    {
539
+        const K = this._camera.intrinsicsMatrix();
540
+
541
+        return ImageTrackerUtils.find6DoFHomographyNDC(K, points, {
542
+            reprojectionError: TRACK_RANSAC_REPROJECTIONERROR_NDC,
543
+            numberOfHypotheses: 100,
544
+            //mask: undefined // score is not needed
545
+        })
546
+        .then(([ warp, score ]) => {
547
+
548
+            const scale = TRACK_RECTIFIED_SCALE;
549
+            const aspectRatio = ImageTrackerUtils.bestFitAspectRatioNDC(this.screenSize, this._referenceImage!);
550
+            const shrink = ImageTrackerUtils.bestFitScaleNDC(aspectRatio, scale);
551
+            const grow = ImageTrackerUtils.inverseBestFitScaleNDC(aspectRatio, scale);
552
+            const scaledWarp = grow.times(warp).times(shrink);
553
+
554
+            //const distort = this._poseHomography;
555
+            const distort = this._warpHomography;
556
+            const undistort = distort.inverse();
557
+            const correctedWarp = distort.times(scaledWarp).times(undistort);
558
+
559
+            return correctedWarp;
560
+
561
+        }).catch(err => {
562
+
563
+            throw new TrackingError(`Can't find a perspective motion`, err);
564
+
565
+        });
566
+    }
567
+
568
+    /**
523 569
      * Find matching pairs of two sets of keypoints matched via brute force
524 570
      * @param srcKeypoints source (database)
525 571
      * @param destKeypoints destination

Loading…
Откажи
Сачувај