ソースを参照

Update scripts

customisations
alemart 1年前
コミット
eced433711
2個のファイルの変更157行の追加198行の削除
  1. 155
    196
      dist/martins.js
  2. 2
    2
      dist/martins.min.js

+ 155
- 196
dist/martins.js ファイルの表示

@@ -5,7 +5,7 @@
5 5
  * https://github.com/alemart/martins-js
6 6
  *
7 7
  * @license LGPL-3.0-or-later
8
- * Date: 2024-07-16T00:44:39.450Z
8
+ * Date: 2024-07-29T00:26:10.319Z
9 9
  */
10 10
 (function webpackUniversalModuleDefinition(root, factory) {
11 11
 	if(typeof exports === 'object' && typeof module === 'object')
@@ -20006,8 +20006,10 @@ class BaseViewport extends ViewportEventTarget {
20006 20006
             container.webkitRequestFullscreen();
20007 20007
             return new (speedy_vision_default()).Promise((resolve, reject) => {
20008 20008
                 setTimeout(() => {
20009
-                    if (container === document.webkitFullscreenElement)
20009
+                    if (container === document.webkitFullscreenElement) {
20010
+                        Utils.log('Entering fullscreen mode...');
20010 20011
                         resolve();
20012
+                    }
20011 20013
                     else
20012 20014
                         reject(new TypeError());
20013 20015
                 }, 100);
@@ -20020,7 +20022,10 @@ class BaseViewport extends ViewportEventTarget {
20020 20022
         return new (speedy_vision_default()).Promise((resolve, reject) => {
20021 20023
             container.requestFullscreen({
20022 20024
                 navigationUI: 'hide'
20023
-            }).then(resolve, reject);
20025
+            }).then(() => {
20026
+                Utils.log('Entering fullscreen mode...');
20027
+                resolve();
20028
+            }, reject);
20024 20029
         });
20025 20030
     }
20026 20031
     /**
@@ -20038,16 +20043,24 @@ class BaseViewport extends ViewportEventTarget {
20038 20043
             doc.webkitExitFullscreen();
20039 20044
             return new (speedy_vision_default()).Promise((resolve, reject) => {
20040 20045
                 setTimeout(() => {
20041
-                    if (doc.webkitFullscreenElement === null)
20046
+                    if (doc.webkitFullscreenElement === null) {
20047
+                        Utils.log('Exiting fullscreen mode...');
20042 20048
                         resolve();
20049
+                    }
20043 20050
                     else
20044 20051
                         reject(new TypeError());
20045 20052
                 }, 100);
20046 20053
             });
20047 20054
         }
20055
+        // error if not in fullscreen mode
20056
+        if (document.fullscreenElement === null)
20057
+            return speedy_vision_default().Promise.reject(new IllegalOperationError('Not in fullscreen mode'));
20048 20058
         // exit fullscreen
20049 20059
         return new (speedy_vision_default()).Promise((resolve, reject) => {
20050
-            document.exitFullscreen().then(resolve, reject);
20060
+            document.exitFullscreen().then(() => {
20061
+                Utils.log('Exiting fullscreen mode...');
20062
+                resolve();
20063
+            }, reject);
20051 20064
         });
20052 20065
     }
20053 20066
     /** Is the fullscreen mode available? */
@@ -23420,18 +23433,14 @@ class ImageTrackerEvent extends AREvent {
23420 23433
 
23421 23434
 
23422 23435
 
23423
-/** Number of samples we'll be keeping to help calibrate the camera */
23424
-const INTRISICS_SAMPLES = 401; //201; //31; // odd number
23425
-/** Whether or not to auto-calibrate the camera */
23426
-const FOVY_AUTODETECT = false; //true;
23427
-/** A guess of the vertical field-of-view of a generic camera, in degrees */
23428
-const FOVY_GUESS = 45; //50; // will be part of the viewing frustum
23436
+/** A guess of the horizontal field-of-view of a typical camera, in degrees */
23437
+const HFOV_GUESS = 60; // https://developer.apple.com/library/archive/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/Cameras/Cameras.html
23429 23438
 /** Number of iterations used to refine the estimated pose */
23430 23439
 const POSE_ITERATIONS = 30;
23431 23440
 /** Number of samples used in the rotation filter */
23432 23441
 const ROTATION_FILTER_SAMPLES = 10;
23433 23442
 /** Number of samples used in the translation filter */
23434
-const TRANSLATION_FILTER_SAMPLES = 10;
23443
+const TRANSLATION_FILTER_SAMPLES = 5;
23435 23444
 /** Convert degrees to radians */
23436 23445
 const DEG2RAD = 0.017453292519943295; // pi / 180
23437 23446
 /** Convert radians to degrees */
@@ -23446,31 +23455,6 @@ const FY = 4;
23446 23455
 const U0 = 6;
23447 23456
 /** Index of the vertical position of the principal point in the camera intrinsics matrix */
23448 23457
 const V0 = 7;
23449
-/** Translation refinement: predefined buffers for efficiency */
23450
-const TRANSLATION_REFINEMENT_BUFFERS = (() => {
23451
-    const l = 1.0;
23452
-    const x = [0, l, 0, -l, 0];
23453
-    const y = [-l, 0, l, 0, 0];
23454
-    const n = x.length;
23455
-    return Object.freeze({
23456
-        x, y,
23457
-        a1: new Array(n),
23458
-        a2: new Array(n),
23459
-        a3: new Array(n),
23460
-        m: new Array(3 * n * 3),
23461
-        v: new Array(3 * n),
23462
-        t: new Array(3),
23463
-        r: new Array(3 * n),
23464
-        c: new Array(3),
23465
-        Mc: new Array(3 * n),
23466
-    });
23467
-})();
23468
-/** Translation refinement: number of iterations */
23469
-const TRANSLATION_REFINEMENT_ITERATIONS = 3; // 1; // 5;
23470
-/** Translation refinement: number of samples */
23471
-const TRANSLATION_REFINEMENT_SAMPLES = 5; // TRANSLATION_REFINEMENT_BUFFERS.x.length;
23472
-/** Translation refinement: the triple of the number of samples */
23473
-const TRANSLATION_REFINEMENT_SAMPLES_3X = 15; //3 * TRANSLATION_REFINEMENT_SAMPLES;
23474 23458
 /**
23475 23459
  * Camera model
23476 23460
  */
@@ -23481,10 +23465,8 @@ class CameraModel {
23481 23465
     constructor() {
23482 23466
         this._screenSize = speedy_vision_default().Size(0, 0);
23483 23467
         this._matrix = speedy_vision_default().Matrix.Eye(3, 4);
23484
-        this._intrinsics = [1, 0, 0, 0, 1, 0, 0, 0, 1]; // identity matrix
23485
-        this._extrinsics = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]; // no rotation & no translation [ R | t ] = [ I | 0 ]
23486
-        this._f = (new Array(INTRISICS_SAMPLES)).fill(this._intrinsics[FY]);
23487
-        this._fp = 0;
23468
+        this._intrinsics = [1, 0, 0, 0, 1, 0, 0, 0, 1]; // 3x3 identity matrix
23469
+        this._extrinsics = [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]; // 3x4 matrix [ R | t ] = [ I | 0 ] no rotation & no translation
23488 23470
         this._partialRotationBuffer = [];
23489 23471
         this._translationBuffer = [];
23490 23472
     }
@@ -23500,8 +23482,7 @@ class CameraModel {
23500 23482
         this._screenSize.width = screenSize.width;
23501 23483
         this._screenSize.height = screenSize.height;
23502 23484
         // reset the model
23503
-        this._resetIntrinsics();
23504
-        this._resetExtrinsics();
23485
+        this.reset();
23505 23486
         // log
23506 23487
         Utils.log(`Initializing the camera model...`);
23507 23488
     }
@@ -23543,18 +23524,13 @@ class CameraModel {
23543 23524
             Utils.warning(`Can't update the camera model using an invalid homography matrix`);
23544 23525
             return speedy_vision_default().Promise.resolve(this._matrix);
23545 23526
         }
23546
-        // estimate the focal length (auto-calibration)
23547
-        const f = this._estimateFocal(homography);
23548
-        if (f > 0)
23549
-            this._storeFocal(f);
23550
-        //console.log(this.fovy * RAD2DEG);
23551 23527
         // estimate the pose
23552 23528
         const pose = this._estimatePose(homography);
23553
-        this._storePose(pose);
23529
+        this._extrinsics = pose.read();
23554 23530
         // compute the camera matrix
23555 23531
         const C = this.denormalizer();
23556 23532
         const K = speedy_vision_default().Matrix(3, 3, this._intrinsics);
23557
-        const E = speedy_vision_default().Matrix(3, 4, this._extrinsics);
23533
+        const E = pose; //Speedy.Matrix(3, 4, this._extrinsics);
23558 23534
         this._matrix.setToSync(K.times(E).times(C));
23559 23535
         //console.log("intrinsics -----------", K.toString());
23560 23536
         //console.log("matrix ----------------",this._matrix.toString());
@@ -23675,81 +23651,38 @@ class CameraModel {
23675 23651
      * Reset camera intrinsics
23676 23652
      */
23677 23653
     _resetIntrinsics() {
23654
+        const cameraWidth = Math.max(this._screenSize.width, this._screenSize.height); // portrait?
23678 23655
         const u0 = this._screenSize.width / 2;
23679 23656
         const v0 = this._screenSize.height / 2;
23680
-        const f = v0 / Math.tan(DEG2RAD * FOVY_GUESS / 2);
23681
-        this._intrinsics[FX] = f;
23682
-        this._intrinsics[FY] = f;
23657
+        const fx = (cameraWidth / 2) / Math.tan(DEG2RAD * HFOV_GUESS / 2);
23658
+        const fy = fx;
23659
+        this._intrinsics[FX] = fx;
23660
+        this._intrinsics[FY] = fy;
23683 23661
         this._intrinsics[U0] = u0;
23684 23662
         this._intrinsics[V0] = v0;
23685
-        this._f.fill(this._intrinsics[FY]);
23686
-        this._fp = 0;
23687
-    }
23688
-    /**
23689
-     * Estimate the focal length
23690
-     * @param homography valid homography
23691
-     * @returns estimated focal length, or 0 on error
23692
-     */
23693
-    _estimateFocal(homography) {
23694
-        // auto-detect the focal length?
23695
-        if (!FOVY_AUTODETECT)
23696
-            return 0;
23697
-        // read the entries of the homography
23698
-        const h = homography.read();
23699
-        const h11 = h[0], h12 = h[3]; //, h13 = h[6];
23700
-        const h21 = h[1], h22 = h[4]; //, h23 = h[7];
23701
-        const h31 = h[2], h32 = h[5]; //, h33 = h[8];
23702
-        // read the principal point
23703
-        const u0 = this._intrinsics[U0];
23704
-        const v0 = this._intrinsics[V0];
23705
-        // estimate the focal length based on the orthogonality
23706
-        // constraint r1'r2 = 0 of a rotation matrix
23707
-        const f2 = -((h11 / h31 - u0) * (h12 / h32 - u0) + (h21 / h31 - v0) * (h22 / h32 - v0));
23708
-        // can't estimate it?
23709
-        if (f2 < 0)
23710
-            return this._intrinsics[FY];
23711
-        //return 0;
23712
-        // done!
23713
-        return Math.sqrt(f2);
23714
-    }
23715
-    /**
23716
-     * Store an estimated focal length
23717
-     * @param f estimated focal length
23718
-     */
23719
-    _storeFocal(f) {
23720
-        // store the focal length
23721
-        this._f[this._fp] = f;
23722
-        this._fp = (this._fp + 1) % INTRISICS_SAMPLES;
23723
-        // take the median of the estimated focal lengths
23724
-        const sorted = this._f.concat([]).sort((a, b) => a - b);
23725
-        const median = sorted[sorted.length >>> 1];
23726
-        // update the intrinsics matrix
23727
-        this._intrinsics[FX] = this._intrinsics[FY] = median;
23728
-        /*
23729
-        // test
23730
-        const u0 = this._intrinsics[U0];
23731
-        const v0 = this._intrinsics[V0];
23732
-        const fovx = 2 * Math.atan(u0 / median) * RAD2DEG;
23733
-        const fovy = 2 * Math.atan(v0 / median) * RAD2DEG;
23734
-        console.log('---------------');
23735
-        console.log("fov:",fovx,fovy);
23736
-        console.log("f:",median);
23737
-        */
23738 23663
     }
23739 23664
     /**
23740
-     * Compute a normalized homography H' = K^(-1) * H for an
23665
+     * Compute a normalized homography H^ = K^(-1) * H for an
23741 23666
      * ideal pinhole with f = 1 and principal point = (0,0)
23742 23667
      * @param homography homography H to be normalized
23743
-     * @param f focal length
23744
-     * @returns normalized homography H'
23668
+     * @returns normalized homography H^
23745 23669
      */
23746
-    _normalizeHomography(homography, f = this._intrinsics[FY]) {
23670
+    _normalizeHomography(homography) {
23747 23671
         const h = homography.read();
23748 23672
         const u0 = this._intrinsics[U0];
23749 23673
         const v0 = this._intrinsics[V0];
23750
-        const h11 = h[0] - u0 * h[2], h12 = h[3] - u0 * h[5], h13 = h[6] - u0 * h[8];
23751
-        const h21 = h[1] - v0 * h[2], h22 = h[4] - v0 * h[5], h23 = h[7] - v0 * h[8];
23752
-        const h31 = h[2] * f, h32 = h[5] * f, h33 = h[8] * f;
23674
+        const fx = this._intrinsics[FX];
23675
+        const fy = this._intrinsics[FY];
23676
+        const u0fx = u0 / fx;
23677
+        const v0fy = v0 / fy;
23678
+        const h11 = h[0] / fx - u0fx * h[2], h12 = h[3] / fx - u0fx * h[5], h13 = h[6] / fx - u0fx * h[8];
23679
+        const h21 = h[1] / fy - v0fy * h[2], h22 = h[4] / fy - v0fy * h[5], h23 = h[7] / fy - v0fy * h[8];
23680
+        const h31 = h[2], h32 = h[5], h33 = h[8];
23681
+        /*console.log([
23682
+            h11, h21, h31,
23683
+            h12, h22, h32,
23684
+            h13, h23, h33,
23685
+        ]);*/
23753 23686
         return speedy_vision_default().Matrix(3, 3, [
23754 23687
             h11, h21, h31,
23755 23688
             h12, h22, h32,
@@ -23766,53 +23699,70 @@ class CameraModel {
23766 23699
         const h11 = h[0], h12 = h[3], h13 = h[6];
23767 23700
         const h21 = h[1], h22 = h[4], h23 = h[7];
23768 23701
         const h31 = h[2], h32 = h[5], h33 = h[8];
23769
-        // select the sign so that t3 = tz > 0
23770
-        const sign = h33 >= 0 ? 1 : -1;
23771
-        // compute the scale factor
23772
-        const h1norm = Math.sqrt(h11 * h11 + h21 * h21 + h31 * h31);
23773
-        const h2norm = Math.sqrt(h12 * h12 + h22 * h22 + h32 * h32);
23774
-        //const scale = sign * 2 / (h1norm + h2norm);
23775
-        //const scale = sign / h1norm;
23776
-        //const scale = sign / h2norm;
23777
-        const scale = sign / Math.max(h1norm, h2norm); // this seems to work. why?
23778
-        // invalid homography?
23779
-        if (Number.isNaN(scale))
23780
-            return speedy_vision_default().Matrix(3, 3, (new Array(9)).fill(Number.NaN));
23702
+        const h1norm2 = h11 * h11 + h21 * h21 + h31 * h31;
23703
+        const h2norm2 = h12 * h12 + h22 * h22 + h32 * h32;
23704
+        const h1norm = Math.sqrt(h1norm2);
23705
+        const h2norm = Math.sqrt(h2norm2);
23706
+        //const hnorm = (h1norm + h2norm) / 2;
23707
+        //const hnorm = Math.sqrt(h1norm * h2norm);
23708
+        const hnorm = Math.max(h1norm, h2norm); // this seems to work. why?
23781 23709
         // we expect h1norm to be approximately h2norm, but sometimes there is a lot of noise
23782 23710
         // if h1norm is not approximately h2norm, it means that the first two columns of
23783 23711
         // the normalized homography are not really encoding a rotation (up to a scale)
23784
-        // what is causing this? does h3 (and h33) tell us anything about it?
23785
-        // what about the intrinsics matrix? the principal point...? the fov...?
23786 23712
         //console.log("h1,h2",h1norm,h2norm);
23787 23713
         //console.log(normalizedHomography.toString());
23788
-        // recover the translation and the rotation
23789
-        const t1 = scale * h13;
23790
-        const t2 = scale * h23;
23791
-        const t3 = scale * h33;
23792
-        const r11 = scale * h11;
23793
-        const r21 = scale * h21;
23794
-        const r31 = scale * h31;
23795
-        const r12 = scale * h12;
23796
-        const r22 = scale * h22;
23797
-        const r32 = scale * h32;
23798
-        // refine the pose
23799
-        const r = this._refineRotation(r11, r21, r31, r12, r22, r32);
23800
-        const t = this._refineTranslation(normalizedHomography, r, [t1, t2, t3]);
23801
-        //const t = [t1, t2, t3]; // faster, but less accurate
23714
+        // compute a rough estimate for the scale factor
23715
+        // select the sign so that t3 = tz > 0
23716
+        const sign = h33 >= 0 ? 1 : -1;
23717
+        let scale = sign / hnorm;
23718
+        // sanity check
23719
+        if (Number.isNaN(scale))
23720
+            return speedy_vision_default().Matrix(3, 3, (new Array(9)).fill(Number.NaN));
23721
+        // recover the rotation
23722
+        let r = new Array(6);
23723
+        r[0] = scale * h11;
23724
+        r[1] = scale * h21;
23725
+        r[2] = scale * h31;
23726
+        r[3] = scale * h12;
23727
+        r[4] = scale * h22;
23728
+        r[5] = scale * h32;
23729
+        // refine the rotation
23730
+        r = this._refineRotation(r); // r is initially noisy
23731
+        /*
23732
+
23733
+        After refining the rotation vectors, let's adjust the scale factor as
23734
+        follows:
23735
+
23736
+        We know that [ r1 | r2 | t ] is equal to the normalized homography H up
23737
+        to a non-zero scale factor s, i.e., [ r1 | r2 | t ] = s H. Let's call M
23738
+        the first two columns of H, i.e., M = [ h1 | h2 ], and R = [ r1 | r2 ].
23739
+        It follows that R = s M, meaning that M'R = s M'M. The trace of 2x2 M'R
23740
+        is such that tr(M'R) = tr(s M'M) = s tr(M'M), which means:
23741
+
23742
+        s = tr(M'R) / tr(M'M) = (r1'h1 + r2'h2) / (h1'h1 + h2'h2)
23743
+
23744
+        (also: s^2 = det(M'R) / det(M'M))
23745
+
23746
+        */
23747
+        // adjust the scale factor
23748
+        scale = r[0] * h11 + r[1] * h21 + r[2] * h31;
23749
+        scale += r[3] * h12 + r[4] * h22 + r[5] * h32;
23750
+        scale /= h1norm2 + h2norm2;
23751
+        // recover the translation
23752
+        let t = new Array(3);
23753
+        t[0] = scale * h13;
23754
+        t[1] = scale * h23;
23755
+        t[2] = scale * h33;
23802 23756
         // done!
23803
-        return speedy_vision_default().Matrix(3, 3, r.concat(t)); // this is possibly NaN... why? homography...
23757
+        return speedy_vision_default().Matrix(3, 3, r.concat(t));
23804 23758
     }
23805 23759
     /**
23806 23760
      * Make two non-zero and non-parallel input vectors, r1 and r2, orthonormal
23807
-     * @param r11 x of r1
23808
-     * @param r21 y of r1
23809
-     * @param r31 z of r1
23810
-     * @param r12 x of r2
23811
-     * @param r22 y of r2
23812
-     * @param r32 z of r2
23761
+     * @param rot rotation vectors [ r1 | r2 ] in column-major format
23813 23762
      * @returns a 3x2 matrix R such that R'R = I (column-major format)
23814 23763
      */
23815
-    _refineRotation(r11, r21, r31, r12, r22, r32) {
23764
+    _refineRotation(rot) {
23765
+        const [r11, r21, r31, r12, r22, r32] = rot;
23816 23766
         /*
23817 23767
 
23818 23768
         A little technique I figured out to correct the rotation vectors
@@ -23925,10 +23875,6 @@ class CameraModel {
23925 23875
         above observation. H, r1, r2 are known.
23926 23876
 
23927 23877
         */
23928
-        const B = TRANSLATION_REFINEMENT_BUFFERS;
23929
-        const n = TRANSLATION_REFINEMENT_SAMPLES;
23930
-        const n3 = TRANSLATION_REFINEMENT_SAMPLES_3X;
23931
-        Utils.assert(B.x.length === n);
23932 23878
         const h = normalizedHomography.read();
23933 23879
         const h11 = h[0], h12 = h[3], h13 = h[6];
23934 23880
         const h21 = h[1], h22 = h[4], h23 = h[7];
@@ -23936,17 +23882,32 @@ class CameraModel {
23936 23882
         const r11 = rot[0], r12 = rot[3];
23937 23883
         const r21 = rot[1], r22 = rot[4];
23938 23884
         const r31 = rot[2], r32 = rot[5];
23939
-        // get sample points (xi, yi), 0 <= i < n
23940
-        const x = B.x, y = B.y;
23885
+        // sample points [ xi  yi ]' in AR screen space
23886
+        //const x = [ 0.5, 0.0, 1.0, 1.0, 0.0, 0.5, 1.0, 0.5, 0.0 ];
23887
+        //const y = [ 0.5, 0.0, 0.0, 1.0, 1.0, 0.0, 0.5, 1.0, 0.5 ];
23888
+        const x = [0.5, 0.0, 1.0, 1.0, 0.0];
23889
+        const y = [0.5, 0.0, 0.0, 1.0, 1.0];
23890
+        const n = x.length;
23891
+        const n3 = 3 * n;
23892
+        const width = this._screenSize.width;
23893
+        const height = this._screenSize.height;
23894
+        for (let i = 0; i < n; i++) {
23895
+            x[i] *= width;
23896
+            y[i] *= height;
23897
+        }
23941 23898
         // set auxiliary values: ai = H [ xi  yi  1 ]'
23942
-        const a1 = B.a1, a2 = B.a2, a3 = B.a3;
23899
+        const a1 = new Array(n);
23900
+        const a2 = new Array(n);
23901
+        const a3 = new Array(n);
23943 23902
         for (let i = 0; i < n; i++) {
23944 23903
             a1[i] = x[i] * h11 + y[i] * h12 + h13;
23945 23904
             a2[i] = x[i] * h21 + y[i] * h22 + h23;
23946 23905
             a3[i] = x[i] * h31 + y[i] * h32 + h33;
23947 23906
         }
23948
-        // solve M t = v for t; M: 3n x 3, v: 3n x 1, t: 3 x 1 (linear least squares)
23949
-        const m = B.m, v = B.v;
23907
+        // we'll solve M t = v for t with linear least squares
23908
+        // M: 3n x 3, v: 3n x 1, t: 3 x 1
23909
+        const m = new Array(3 * n * 3);
23910
+        const v = new Array(3 * n);
23950 23911
         for (let i = 0, k = 0; k < n; i += 3, k++) {
23951 23912
             m[i] = m[i + n3 + 1] = m[i + n3 + n3 + 2] = 0;
23952 23913
             m[i + n3] = -(m[i + 1] = a3[k]);
@@ -24003,14 +23964,20 @@ class CameraModel {
24003 23964
         where c = A'r = A'(Ax - b)
24004 23965
 
24005 23966
         */
23967
+        // gradient descent: super lightweight implementation
23968
+        const r = new Array(3 * n);
23969
+        const c = new Array(3);
23970
+        const Mc = new Array(3 * n);
24006 23971
         // initial guess
24007
-        const t = B.t;
23972
+        const t = new Array(3);
24008 23973
         t[0] = t0[0];
24009 23974
         t[1] = t0[1];
24010 23975
         t[2] = t0[2];
24011
-        // gradient descent: super lightweight implementation
24012
-        const r = B.r, c = B.c, Mc = B.Mc;
24013
-        for (let it = 0; it < TRANSLATION_REFINEMENT_ITERATIONS; it++) {
23976
+        // iterate
23977
+        const MAX_ITERATIONS = 15;
23978
+        const TOLERANCE = 1;
23979
+        for (let it = 0; it < MAX_ITERATIONS; it++) {
23980
+            //console.log("it",it+1);
24014 23981
             // compute residual r = Mt - v
24015 23982
             for (let i = 0; i < n3; i++) {
24016 23983
                 r[i] = 0;
@@ -24030,17 +23997,22 @@ class CameraModel {
24030 23997
                 for (let j = 0; j < 3; j++)
24031 23998
                     Mc[i] += m[j * n3 + i] * c[j];
24032 23999
             }
24033
-            // compute num = c'c and den = (Mc)'(Mc)
24034
-            let num = 0, den = 0;
24000
+            // compute c'c
24001
+            let num = 0;
24035 24002
             for (let i = 0; i < 3; i++)
24036 24003
                 num += c[i] * c[i];
24004
+            //console.log("c'c=",num);
24005
+            if (num < TOLERANCE)
24006
+                break;
24007
+            // compute (Mc)'(Mc)
24008
+            let den = 0;
24037 24009
             for (let i = 0; i < n3; i++)
24038 24010
                 den += Mc[i] * Mc[i];
24039
-            // compute num / den
24011
+            // compute frc = c'c / (Mc)'(Mc)
24040 24012
             const frc = num / den;
24041
-            if (Number.isNaN(frc))
24013
+            if (Number.isNaN(frc)) // this shouldn't happen
24042 24014
                 break;
24043
-            // iterate: t = t - (num / den) * c
24015
+            // iterate: t = t - frc * c
24044 24016
             for (let i = 0; i < 3; i++)
24045 24017
                 t[i] -= frc * c[i];
24046 24018
         }
@@ -24084,7 +24056,7 @@ class CameraModel {
24084 24056
             for (let j = 0; j < 6; j++)
24085 24057
                 avg[j] += r[j] / n;
24086 24058
         }
24087
-        const r = this._refineRotation(avg[0], avg[1], avg[2], avg[3], avg[4], avg[5]);
24059
+        const r = this._refineRotation(avg);
24088 24060
         // average translations
24089 24061
         const m = this._translationBuffer.length;
24090 24062
         for (let i = 0; i < m; i++) {
@@ -24129,51 +24101,38 @@ class CameraModel {
24129 24101
     /**
24130 24102
      * Estimate the pose [ R | t ] given a homography in AR screen space
24131 24103
      * @param homography must be valid
24132
-     * @param f focal length
24133 24104
      * @returns 3x4 matrix
24134 24105
      */
24135
-    _estimatePose(homography, f = this._intrinsics[FY]) {
24136
-        const normalizedHomography = this._normalizeHomography(homography, f);
24106
+    _estimatePose(homography) {
24107
+        const normalizedHomography = this._normalizeHomography(homography);
24137 24108
         const partialPose = speedy_vision_default().Matrix.Eye(3);
24138 24109
         // we want the estimated partial pose [ r1 | r2 | t ] to be as close
24139 24110
         // as possible to the normalized homography, up to a scale factor;
24140 24111
         // i.e., H * [ r1 | r2 | t ]^(-1) = s * I for a non-zero scalar s
24141
-        // it won't be a perfect equality due to noise in the homography
24112
+        // it won't be a perfect equality due to noise in the homography.
24113
+        // remark: composition of homographies
24142 24114
         const residual = speedy_vision_default().Matrix(normalizedHomography);
24143 24115
         for (let k = 0; k < POSE_ITERATIONS; k++) {
24144 24116
             // incrementally improve the partial pose
24145 24117
             const rt = this._estimatePartialPose(residual); // rt should converge to the identity matrix
24146 24118
             partialPose.setToSync(rt.times(partialPose));
24147 24119
             residual.setToSync(residual.times(rt.inverse()));
24120
+            //console.log("rt",rt.toString());
24148 24121
             //console.log("residual",residual.toString());
24149 24122
         }
24150 24123
         //console.log('-----------');
24151
-        /*
24152
-        // test
24153
-        const result = Speedy.Matrix.Zeros(3);
24154
-        result.setToSync(partialPose.times(normalizedHomography.inverse()));
24155
-        const m11 = result.at(0,0);
24156
-        result.setToSync(result.times(1/m11));
24157
-        console.log("Pose * NORMALIZED HOM^-1", result.toString());
24158
-        */
24159
-        /*
24160
-        const rt = partialPose.read();
24161
-        const r = rt.slice(0, 6);
24162
-        const t = this._refineTranslation(normalizedHomography, r, rt.slice(6, 9));
24163
-        const refinedPartialPose = Speedy.Matrix(3, 3, r.concat(t));
24164
-        const filteredPartialPose = this._filterPartialPose(refinedPartialPose);
24165
-        */
24124
+        // refine the translation vector
24125
+        const mat = partialPose.read();
24126
+        const r = mat.slice(0, 6);
24127
+        const t0 = mat.slice(6, 9);
24128
+        const t = this._refineTranslation(normalizedHomography, r, t0);
24129
+        const refinedPartialPose = speedy_vision_default().Matrix(3, 3, r.concat(t));
24166 24130
         // filter the partial pose
24167
-        const filteredPartialPose = this._filterPartialPose(partialPose);
24131
+        const filteredPartialPose = this._filterPartialPose(refinedPartialPose);
24168 24132
         // estimate the full pose
24169
-        return this._estimateFullPose(filteredPartialPose);
24170
-    }
24171
-    /**
24172
-     * Store an estimated pose
24173
-     * @param pose 3x4 matrix
24174
-     */
24175
-    _storePose(pose) {
24176
-        this._extrinsics = pose.read();
24133
+        //const finalPartialPose = partialPose;
24134
+        const finalPartialPose = filteredPartialPose;
24135
+        return this._estimateFullPose(finalPartialPose);
24177 24136
     }
24178 24137
 }
24179 24138
 

+ 2
- 2
dist/martins.min.js
ファイル差分が大きすぎるため省略します
ファイルの表示


読み込み中…
キャンセル
保存