4点图像变换
我想实现这样的事情:https://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript4点图像变换
我基本上要给出4分的时候在透视正确的方式变换的图像。我对3D转换的知识相当有限,所以我很难在使用PerspectiveCamera
时正确定位图像。
我不需要能够拖动终点,我只是想轻松定义那种转换。
我不想用three.js做这件事,而不使用css转换的原因是我需要更高的浏览器支持和事后保存图片的能力,所以我想用CanvasRenderer
。
好的,经过大量的试用后,我发现了一种主要起作用的方式。
我用这个代码从这个实现中进行了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
));
这工作perfektly。窍门是image.applyMatrix(new THREE.Matrix4().makeTranslation(imageWidth/2, imageHeight/2, 0));
以algorythm期望的方式移动转换起点。这个例子确实包括了transform-origin: 0 0;
,这在我的第一次尝试中就不存在了。
相机只是一个简单的THREE.OrthographicCamera
所以没有fov的问题。
所以现在这个解决方案的唯一问题:似乎使用投影Three.js将导致图像不正确拟合。因此,按照我原来的计划使用CanvasRenderer
无法正常工作。
我可以尝试调整图像,以便它可能再次适合,但webgl渲染器现在与我很好。但由于我现在有一个画布,我可以使用toBlob
方法,并让用户保存图像,而无需服务器往返,这是我想要的。
@Width threejs有一个使用2d函数的画布渲染器,所以不需要webgl。如果我刚刚获得了转型权,那么工作得很好。 – Nemo64
@好吧,所以浏览器的支持不是重点,但是能够保存图像是重点。我需要能够保存为jpeg。我知道imagemagick支持这种转换,但比我需要服务器往返+用户放置在占位符中的图像的上传。我可以做到这一点,但如果我可以在画布上绘制它,然后使用FileSaver.js来保存它,它会更好。 – Nemo64
如果你想要这个与透视摄像头一起工作,看看http://jsdo.it/makc/2aVN但我想你根本不需要three.js – makc