4点图像变换

时间:2016-04-27 14:37:58

标签: javascript 3d three.js

我正在尝试实现以下内容:https://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript

我基本上想要在给出4个点时以透视正确的方式转换图像。我对3d变换的了解相当有限,所以在使用PerspectiveCamera时我已经很难正确定位图像。

我不需要能够拖动终点,我只想轻松定义那种转换。

我不想用three.js做这个并且不使用css转换的原因是我需要更高的浏览器支持以及之后保存图像的能力所以我想使用CanvasRenderer。< / p>

1 个答案:

答案 0 :(得分:1)

好的,经过大量的试验,我找到了一种主要有用的方法。

我使用此实现中的代码进行css转换http://jsfiddle.net/dFrHS/1/并更改它以便返回Matrix4。

        function adj(m) { // Compute the adjugate of m
            return [
                m[4]*m[8]-m[5]*m[7], m[2]*m[7]-m[1]*m[8], m[1]*m[5]-m[2]*m[4],
                m[5]*m[6]-m[3]*m[8], m[0]*m[8]-m[2]*m[6], m[2]*m[3]-m[0]*m[5],
                m[3]*m[7]-m[4]*m[6], m[1]*m[6]-m[0]*m[7], m[0]*m[4]-m[1]*m[3]
            ];
        }
        function multmm(a, b) { // multiply two matrices
            var c = Array(9);
            for (var i = 0; i != 3; ++i) {
                for (var j = 0; j != 3; ++j) {
                    var cij = 0;
                    for (var k = 0; k != 3; ++k) {
                        cij += a[3*i + k]*b[3*k + j];
                    }
                    c[3*i + j] = cij;
                }
            }
            return c;
        }
        function multmv(m, v) { // multiply matrix and vector
            return [
                m[0]*v[0] + m[1]*v[1] + m[2]*v[2],
                m[3]*v[0] + m[4]*v[1] + m[5]*v[2],
                m[6]*v[0] + m[7]*v[1] + m[8]*v[2]
            ];
        }
        function basisToPoints(x1, y1, x2, y2, x3, y3, x4, y4) {
            var m = [
                x1, x2, x3,
                y1, y2, y3,
                1,  1,  1
            ];
            var v = multmv(adj(m), [x4, y4, 1]);
            return multmm(m, [
                v[0], 0, 0,
                0, v[1], 0,
                0, 0, v[2]
            ]);
        }
        function general2DProjection(
                x1s, y1s, x1d, y1d,
                x2s, y2s, x2d, y2d,
                x3s, y3s, x3d, y3d,
                x4s, y4s, x4d, y4d
        ) {
            var s = basisToPoints(x1s, y1s, x2s, y2s, x3s, y3s, x4s, y4s);
            var d = basisToPoints(x1d, y1d, x2d, y2d, x3d, y3d, x4d, y4d);
            return multmm(d, adj(s));
        }
        function project(m, x, y) {
            var v = multmv(m, [x, y, 1]);
            return [v[0]/v[2], v[1]/v[2]];
        }
        function transform2d(w, h, x1, y1, x2, y2, x3, y3, x4, y4) {
            var t = general2DProjection
            (0, 0, x1, y1, w, 0, x2, y2, 0, h, x3, y3, w, h, x4, y4);
            for(i = 0; i != 9; ++i) t[i] = t[i]/t[8];
            var matrix = new THREE.Matrix4();
            matrix.fromArray([
                t[0], t[3], 0, t[6],
                t[1], t[4], 0, t[7],
                0   , 0   , 1, 0   ,
                t[2], t[5], 0, t[8]
            ]);
            return matrix;
        }

然后我可以创建我想要变换的图像:

        var imageWidth = 650;
        var imageHeight = 925;
        var texture = new THREE.TextureLoader().load("2b. neue Anzeige für BP.jpg");
        var material = new THREE.MeshBasicMaterial({map: texture, overdraw: 0.5});
        var planeGeometry = new THREE.PlaneGeometry(imageWidth, imageHeight, 10, 10);
        var image = new THREE.Mesh(planeGeometry, material);

        image.matrixAutoUpdate = false;
        image.applyMatrix(new THREE.Matrix4().makeTranslation(imageWidth / 2, imageHeight / 2, 0));
        image.applyMatrix(transform2d(
                imageWidth, imageHeight,
                -180, -373,
                72, -242,
                -395, -63,
                -145, 35
        ));

这完全可行。诀窍是image.applyMatrix(new THREE.Matrix4().makeTranslation(imageWidth / 2, imageHeight / 2, 0));以一种algorythm预期的方式移动转换起源。该示例确实包含transform-origin: 0 0;,并且在我的第一次尝试中失踪了。

相机只是一个简单的THREE.OrthographicCamera,所以没有fov问题。

所以现在这个解决方案唯一的问题是:使用Pro.of Three.js似乎会导致图像不正确。因此,使用我原先计划的CanvasRenderer无效。

我可以尝试调整图像以便它可以再次适合但是webgl渲染器现在对我很好。但是因为我现在有一个画布,我可以使用toBlob方法让用户保存图像而不需要服务器往返,这就是我想要的。