2

我正在尝试将OpenCVWebGL一起使用。

OpenCV中,我正在寻找使用 SolvePnp 获得的投影(相机的先验投影矩阵)。当我使用“projectPoints”函数显示在 OpenCV 中获得的投影时,一切都完全停止了。

在此处输入图像描述

SolvePnp函数返回 3值用于旋转和 3 个值用于平移。我还使用值fx、fy、cx、cy(参见:https ://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#solvepnp)得到了cameraMatrix(矩阵3x3 )。

一旦所有这些值都恢复了,我尝试将它们与WebGL一起使用。但目前它不起作用。


在 WebGL 中,我以两种不同的方式计算projectionMatrix :

m4.perspective (28 / 180.0 * Math.PI, aspect, 0.1, 1000);

或通过以下示例(https://blog.noctua-software.com/opencv-opengl-projection-matrix.html

openCVToProjectionMatrix (fx, fy, cx, cy, 0.1, 1000, wSource, hSource);

然后我创建了cameraMatrix并将从 OpenCV 恢复的值应用于它。
我通过执行inverseMatrix来计算ViewMatrix。 然后我通过将projectionMatrix乘以viewMatrix来计算viewProjectionMatrix。 我通过简单的 viewProjectionMatrix 计算ModelMatrix。 我在我的计划(2个三角形)上应用了以下值:


var size = 1.0 x: -size * 0.5 y: -size * 0.5 width: size height: size

然后我补充说:

gl.uniformMatrix4fv (matrixLocation, false, matrixModel)

不幸的是,它不起作用。


我的问题

我是否正确应用了这些矩阵,或者在这个级别上是否有任何错误?
还有其他参数需要考虑吗?
我必须在相机上应用翻译吗?
矩阵计算是否有顺序(从比例开始,然后是旋转,最后是平移)?
最后,有人可以帮助我吗?


代码示例

// Source Dimensions(Webcam)
var wSrc = 360, hSrc = 640;
// Trigger Dimensions
var wTrigger = 602, hTrigger = 452;
// OpenCV values for projectionMatrix
var fx = 603.92035729, fy = 605.26722937;
var cx = 179.804103189, cy = 320.14721692;

// Values from SolvePnp(openCV)
var rVecs = [0.464472599644,-0.210231064819,-0.0689626255534];
var tVecs = [-0.61758832993,-0.567979295625,2.78430675542];

// -------------------------------------------------------------------------------------
var vertexShader = `
	attribute vec4 a_position;
	attribute vec4 a_color;
	uniform mat4 u_matrix;
	
	void main() {
		// Multiply the position by the matrix.
		gl_Position = u_matrix * a_position;
	}
`;

// -------------------------------------------------------------------------------------
var fragmentShader = `
	precision mediump float;

	void main() {
		gl_FragColor = vec4(1, 0, 0, 1);
	}
`;



// *************************************************************************************
// *************************************************************************************
// *************************************************************************************
var m4 = {

  perspective: function(fieldOfViewInRadians, aspect, near, far) {
    var f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewInRadians);
    var rangeInv = 1.0 / (near - far);

    return [
      f / aspect, 0, 0, 0,
      0, f, 0, 0,
      0, 0, (near + far) * rangeInv, -1,
      0, 0, near * far * rangeInv * 2, 0
    ];
  },

  projection: function(width, height, depth) {
    // Note: This matrix flips the Y axis so 0 is at the top.
    return [
       2 / width, 0, 0, 0,
       0, -2 / height, 0, 0,
       0, 0, 2 / depth, 0,
      -1, 1, 0, 1,
    ];
  },

  multiply: function(a, b) {
    var a00 = a[0 * 4 + 0];
    var a01 = a[0 * 4 + 1];
    var a02 = a[0 * 4 + 2];
    var a03 = a[0 * 4 + 3];
    var a10 = a[1 * 4 + 0];
    var a11 = a[1 * 4 + 1];
    var a12 = a[1 * 4 + 2];
    var a13 = a[1 * 4 + 3];
    var a20 = a[2 * 4 + 0];
    var a21 = a[2 * 4 + 1];
    var a22 = a[2 * 4 + 2];
    var a23 = a[2 * 4 + 3];
    var a30 = a[3 * 4 + 0];
    var a31 = a[3 * 4 + 1];
    var a32 = a[3 * 4 + 2];
    var a33 = a[3 * 4 + 3];
    var b00 = b[0 * 4 + 0];
    var b01 = b[0 * 4 + 1];
    var b02 = b[0 * 4 + 2];
    var b03 = b[0 * 4 + 3];
    var b10 = b[1 * 4 + 0];
    var b11 = b[1 * 4 + 1];
    var b12 = b[1 * 4 + 2];
    var b13 = b[1 * 4 + 3];
    var b20 = b[2 * 4 + 0];
    var b21 = b[2 * 4 + 1];
    var b22 = b[2 * 4 + 2];
    var b23 = b[2 * 4 + 3];
    var b30 = b[3 * 4 + 0];
    var b31 = b[3 * 4 + 1];
    var b32 = b[3 * 4 + 2];
    var b33 = b[3 * 4 + 3];
    return [
      b00 * a00 + b01 * a10 + b02 * a20 + b03 * a30,
      b00 * a01 + b01 * a11 + b02 * a21 + b03 * a31,
      b00 * a02 + b01 * a12 + b02 * a22 + b03 * a32,
      b00 * a03 + b01 * a13 + b02 * a23 + b03 * a33,
      b10 * a00 + b11 * a10 + b12 * a20 + b13 * a30,
      b10 * a01 + b11 * a11 + b12 * a21 + b13 * a31,
      b10 * a02 + b11 * a12 + b12 * a22 + b13 * a32,
      b10 * a03 + b11 * a13 + b12 * a23 + b13 * a33,
      b20 * a00 + b21 * a10 + b22 * a20 + b23 * a30,
      b20 * a01 + b21 * a11 + b22 * a21 + b23 * a31,
      b20 * a02 + b21 * a12 + b22 * a22 + b23 * a32,
      b20 * a03 + b21 * a13 + b22 * a23 + b23 * a33,
      b30 * a00 + b31 * a10 + b32 * a20 + b33 * a30,
      b30 * a01 + b31 * a11 + b32 * a21 + b33 * a31,
      b30 * a02 + b31 * a12 + b32 * a22 + b33 * a32,
      b30 * a03 + b31 * a13 + b32 * a23 + b33 * a33,
    ];
  },
	
  
  translation: function(tx, ty, tz) {
    return [
       1,  0,  0,  0,
       0,  1,  0,  0,
       0,  0,  1,  0,
       tx, ty, tz, 1,
    ];
  },

  xRotation: function(angleInRadians) {
    var c = Math.cos(angleInRadians);
    var s = Math.sin(angleInRadians);

    return [
      1, 0, 0, 0,
      0, c, s, 0,
      0, -s, c, 0,
      0, 0, 0, 1,
    ];
  },

  yRotation: function(angleInRadians) {
    var c = Math.cos(angleInRadians);
    var s = Math.sin(angleInRadians);

    return [
      c, 0, -s, 0,
      0, 1, 0, 0,
      s, 0, c, 0,
      0, 0, 0, 1,
    ];
  },

  zRotation: function(angleInRadians) {
    var c = Math.cos(angleInRadians);
    var s = Math.sin(angleInRadians);

    return [
       c, s, 0, 0,
      -s, c, 0, 0,
       0, 0, 1, 0,
       0, 0, 0, 1,
    ];
  },

  
  scaling: function(sx, sy, sz) {
    return [
      sx, 0,  0,  0,
      0, sy,  0,  0,
      0,  0, sz,  0,
      0,  0,  0,  1,
    ];
  },

  
  translate: function(m, tx, ty, tz) {
    return m4.multiply(m, m4.translation(tx, ty, tz));
  },

  
  xRotate: function(m, angleInRadians) {
    return m4.multiply(m, m4.xRotation(angleInRadians));
  },

  yRotate: function(m, angleInRadians) {
    return m4.multiply(m, m4.yRotation(angleInRadians));
  },

  zRotate: function(m, angleInRadians) {
    return m4.multiply(m, m4.zRotation(angleInRadians));
  },

  
  scale: function(m, sx, sy, sz) {
    return m4.multiply(m, m4.scaling(sx, sy, sz));
  },

  
  inverse: function(m) {
    var m00 = m[0 * 4 + 0];
    var m01 = m[0 * 4 + 1];
    var m02 = m[0 * 4 + 2];
    var m03 = m[0 * 4 + 3];
    var m10 = m[1 * 4 + 0];
    var m11 = m[1 * 4 + 1];
    var m12 = m[1 * 4 + 2];
    var m13 = m[1 * 4 + 3];
    var m20 = m[2 * 4 + 0];
    var m21 = m[2 * 4 + 1];
    var m22 = m[2 * 4 + 2];
    var m23 = m[2 * 4 + 3];
    var m30 = m[3 * 4 + 0];
    var m31 = m[3 * 4 + 1];
    var m32 = m[3 * 4 + 2];
    var m33 = m[3 * 4 + 3];
    var tmp_0  = m22 * m33;
    var tmp_1  = m32 * m23;
    var tmp_2  = m12 * m33;
    var tmp_3  = m32 * m13;
    var tmp_4  = m12 * m23;
    var tmp_5  = m22 * m13;
    var tmp_6  = m02 * m33;
    var tmp_7  = m32 * m03;
    var tmp_8  = m02 * m23;
    var tmp_9  = m22 * m03;
    var tmp_10 = m02 * m13;
    var tmp_11 = m12 * m03;
    var tmp_12 = m20 * m31;
    var tmp_13 = m30 * m21;
    var tmp_14 = m10 * m31;
    var tmp_15 = m30 * m11;
    var tmp_16 = m10 * m21;
    var tmp_17 = m20 * m11;
    var tmp_18 = m00 * m31;
    var tmp_19 = m30 * m01;
    var tmp_20 = m00 * m21;
    var tmp_21 = m20 * m01;
    var tmp_22 = m00 * m11;
    var tmp_23 = m10 * m01;

    var t0 = (tmp_0 * m11 + tmp_3 * m21 + tmp_4 * m31) -
        (tmp_1 * m11 + tmp_2 * m21 + tmp_5 * m31);
    var t1 = (tmp_1 * m01 + tmp_6 * m21 + tmp_9 * m31) -
        (tmp_0 * m01 + tmp_7 * m21 + tmp_8 * m31);
    var t2 = (tmp_2 * m01 + tmp_7 * m11 + tmp_10 * m31) -
        (tmp_3 * m01 + tmp_6 * m11 + tmp_11 * m31);
    var t3 = (tmp_5 * m01 + tmp_8 * m11 + tmp_11 * m21) -
        (tmp_4 * m01 + tmp_9 * m11 + tmp_10 * m21);

    var d = 1.0 / (m00 * t0 + m10 * t1 + m20 * t2 + m30 * t3);

    return [
      d * t0,
      d * t1,
      d * t2,
      d * t3,
      d * ((tmp_1 * m10 + tmp_2 * m20 + tmp_5 * m30) -
            (tmp_0 * m10 + tmp_3 * m20 + tmp_4 * m30)),
      d * ((tmp_0 * m00 + tmp_7 * m20 + tmp_8 * m30) -
            (tmp_1 * m00 + tmp_6 * m20 + tmp_9 * m30)),
      d * ((tmp_3 * m00 + tmp_6 * m10 + tmp_11 * m30) -
            (tmp_2 * m00 + tmp_7 * m10 + tmp_10 * m30)),
      d * ((tmp_4 * m00 + tmp_9 * m10 + tmp_10 * m20) -
            (tmp_5 * m00 + tmp_8 * m10 + tmp_11 * m20)),
      d * ((tmp_12 * m13 + tmp_15 * m23 + tmp_16 * m33) -
            (tmp_13 * m13 + tmp_14 * m23 + tmp_17 * m33)),
      d * ((tmp_13 * m03 + tmp_18 * m23 + tmp_21 * m33) -
            (tmp_12 * m03 + tmp_19 * m23 + tmp_20 * m33)),
      d * ((tmp_14 * m03 + tmp_19 * m13 + tmp_22 * m33) -
            (tmp_15 * m03 + tmp_18 * m13 + tmp_23 * m33)),
      d * ((tmp_17 * m03 + tmp_20 * m13 + tmp_23 * m23) -
            (tmp_16 * m03 + tmp_21 * m13 + tmp_22 * m23)),
      d * ((tmp_14 * m22 + tmp_17 * m32 + tmp_13 * m12) -
            (tmp_16 * m32 + tmp_12 * m12 + tmp_15 * m22)),
      d * ((tmp_20 * m32 + tmp_12 * m02 + tmp_19 * m22) -
            (tmp_18 * m22 + tmp_21 * m32 + tmp_13 * m02)),
      d * ((tmp_18 * m12 + tmp_23 * m32 + tmp_15 * m02) -
            (tmp_22 * m32 + tmp_14 * m02 + tmp_19 * m12)),
      d * ((tmp_22 * m22 + tmp_16 * m02 + tmp_21 * m12) -
            (tmp_20 * m12 + tmp_23 * m22 + tmp_17 * m02))
    ];
  },

  
  vectorMultiply: function(v, m) {
    var dst = [];
    for (var i = 0; i < 4; ++i) {
      dst[i] = 0.0;
      for (var j = 0; j < 4; ++j)
        dst[i] += v[j] * m[j * 4 + i];
    }
    return dst;
  },

};



// *************************************************************************************
// *************************************************************************************
// *************************************************************************************
initGL();

// -------------------------------------------------------------------------------------
function initializeWebGL(canvasName) {
    var canvas = document.getElementById(canvasName);

    var gl = null;

    try {
        gl = canvas.getContext("webgl");
    } 
	  catch (error) {
        console.log("Error getContext WebGL", error);
    }
	
    if (!gl) {
        throw new Error("Could not get WebGL context!");
    }
	
    return gl;
}

function createShader(gl, shaderSource, shaderType) {
    var shader = gl.createShader(shaderType);
    gl.shaderSource(shader, shaderSource);
    gl.compileShader(shader);
	
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        var infoLog = gl.getShaderInfoLog(shader);
        gl.deleteShader(shader);
        throw new Error("An error occurred compiling the shader: " + infoLog);
    } 
	else {
        return shader;
    }
}

function createGlslProgram(gl, vertexSource, fragmentSource) {
    var program = gl.createProgram();
    gl.attachShader(program, createShader(gl, vertexSource, gl.VERTEX_SHADER));
    gl.attachShader(program, createShader(gl, fragmentSource, gl.FRAGMENT_SHADER));
    gl.linkProgram(program);
    gl.validateProgram(program);
    
	if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
        var infoLog = gl.getProgramInfoLog(program);
        gl.deleteProgram(program);
        throw new Error("An error occurred linking the program: " + infoLog);
    } 
	else {
        return program;
    }
}




// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------

function initGL() {
	var gl = initializeWebGL("canvasGL");
	var program = createGlslProgram(gl, vertexShader, fragmentShader);
	
	
	// ------------------------------------------------------------------------------
	resizeCanvasToDisplaySize(gl.canvas, window.devicePixelRatio);
	
	
	// ------------------------------------------------------------------------------
	var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
	var matrixLocation = gl.getUniformLocation(program, "u_matrix");
	var positionBuffer = gl.createBuffer();
	
	
	// ------------------------------------------------------------------------------
	gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
	gl.clearColor(0, 0, 0, 0);
	gl.clear(gl.COLOR_BUFFER_BIT);

	
	// ------------------------------------------------------------------------------
	gl.useProgram(program);
	
	
	// ------------------------------------------------------------------------------
	gl.enableVertexAttribArray(positionAttributeLocation);
	gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
	
	// ------------------------------------------------------------------------------
	initFlatPlane(gl, positionAttributeLocation, matrixLocation);
}



function initFlatPlane(gl, positionAttributeLocation, matrixLocation){
	var size = 3;
	var type = gl.FLOAT;
	var normalize = false;
	var stride = 0;
	var offset = 0;
	gl.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset)
	
  
	// ------------------------------------------------------------------------------
	// projectionMatrix
	var matOpenCV = openCVCameraMatrixToProjectionMatrix(fx, fy, cx, cy, 1000, 0.1, wSrc, hSrc);
	var projectionMatrix = matOpenCV[0].concat(matOpenCV[1]).concat(matOpenCV[2]).concat(matOpenCV[3]);
	console.log("projectionMatrix :", projectionMatrix);
	
	// ------------------------------------------------------------------------------
	// Compute a matrix for the camera
	var cameraMatrix = [1, 0, 0, 0,  0, 1, 0, 0,  0, 0, 1, 0,  0, 0, 0, 1];
	cameraMatrix = m4.scale(cameraMatrix, 1, wTrigger/hTrigger, 1);
	cameraMatrix = m4.xRotate(cameraMatrix, rVecs[0]);
	cameraMatrix = m4.yRotate(cameraMatrix, rVecs[1]);
	cameraMatrix = m4.zRotate(cameraMatrix, rVecs[2]);
	cameraMatrix = m4.translate(cameraMatrix, tVecs[0], tVecs[1], tVecs[2]);
	console.log("cameraMatrix", cameraMatrix);
	
	// ------------------------------------------------------------------------------
	// Make a view matrix from the camera matrix
	var viewMatrix = m4.inverse(cameraMatrix);
	console.log("viewMatrix", viewMatrix);
	
	// ------------------------------------------------------------------------------
	// Compute a view projection matrix
	var viewProjectionMatrix = m4.multiply(projectionMatrix, viewMatrix);
	console.log("viewProjectionMatrix", viewProjectionMatrix);
	
	// ------------------------------------------------------------------------------
	// modelMatrix
	var modelMatrix = m4.translate(viewProjectionMatrix, 0.0, 0.0, 0.0);
	console.log("modelMatrix", modelMatrix);
	
	
	// ------------------------------------------------------------------------------
	var size = 1.0
	setRectangle(gl, -size * .5, -size * .5, size, size);
	
	// Let modelMatrix
	gl.uniformMatrix4fv(matrixLocation, false, modelMatrix);
	
	// Draw
	var primitiveType = gl.TRIANGLES;
	var offset = 0;
	var count = 6;
	gl.drawArrays(primitiveType, offset, count);
}


function setRectangle(gl, x, y, width, height) {
	var x1 = x;
	var x2 = x + width;
	var y1 = y;
	var y2 = y + height;
	var z = 0;
	
	gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
		x1, y1, z,
		x2, y1, z,
		x1, y2, z,
		x1, y2, z,
		x2, y1, z,
		x2, y2, z,
	]), gl.STATIC_DRAW);
}


function resizeCanvasToDisplaySize(canvas, multiplier) {
	multiplier = multiplier || 1;
	var width  = canvas.clientWidth  * multiplier | 0;
	var height = canvas.clientHeight * multiplier | 0;
	if (canvas.width !== width ||  canvas.height !== height) {
		canvas.width  = width;
		canvas.height = height;
		return true;
	}
	return false;
}


function openCVCameraMatrixToProjectionMatrix(fx, fy, cx, cy, zfar, znear, width, height){
	var m = [
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0],
		[0, 0, 0, 0],
	];
	
	m[0][0] = 2.0 * fx / width;
	m[0][1] = 0.0;
	m[0][2] = 0.0;
	m[0][3] = 0.0;

	m[1][0] = 0.0;
	m[1][1] = -2.0 * fy / height;
	m[1][2] = 0.0;
	m[1][3] = 0.0;

	m[2][0] = 1.0 - 2.0 * cx / width;
	m[2][1] = 2.0 * cy / height - 1.0;
	m[2][2] = (zfar + znear) / (znear - zfar);
	m[2][3] = -1.0;

	m[3][0] = 0.0;
	m[3][1] = 0.0;
	m[3][2] = 2.0 * zfar * znear / (znear - zfar);
	m[3][3] = 0.0;
	
	return m;
}
body {
    margin:0;
    padding:0;
    background-color:lightgray;
  }

  #canvasGL, img {
    position:absolute;
    width:360px;
    height:640px;
  }
  img {
    opacity: 0.2;
  }

  #canvasBackground {
    border: solid 1px darkGray;
  }
<body>
	<img src="http://www.indelebil.fr/tmp/preview_python_02.jpg" />
	<canvas id="canvasGL"></canvas>
</body>

结果

在此处输入图像描述


谢谢你的帮助 !!!!

4

0 回答 0