我想做简单的fisheye算法,让它看起来像屏幕镜头。这是画布的简单javascript代码。
var frame = context.getImageData(0, 0, canvas.width, canvas.height); var source = new Uint8ClampedArray(frame.data); context2.clearRect(0, 0, canvas.width, canvas.height); const SIZE = 80; for (var i = 0; i < frame.data.length; i += 4) { var x = (i / 4) % frame.width; var y = Math.floor(i / 4 / frame.width); let mouseX = frame.width / 2; let mouseY = frame.height / 2; var dx = mouseX - x; var dy = mouseY - y; var dist = Math.sqrt(dx * dx + dy * dy); var i2 = i; if (dist <= SIZE) { var x2 = Math.round( mouseX - dx * Math.sin(((dist / SIZE) * Math.PI) / 2) ); var y2 = Math.round( mouseY - dy * Math.sin(((dist / SIZE) * Math.PI) / 2) ); var i2 = (y2 * frame.width + x2) * 4; } frame.data[i] = source[i2]; frame.data[i + 1] = source[i2 + 1]; frame.data[i + 2] = source[i2 + 2]; frame.data[i + 3] = source[i2 + 3]; } context2.putImageData(frame, 0, 0);
您看到的是被镜头效果放大的源像素。它们具有硬边,因为您照此复制像素值,所以保留了这些边。您正在做的事情被称为“最近邻插值”。
您将通过“双线性插值”获得更平滑的结果。
公式是
(1-v) ((1-u) V00 + u V10) + v ((1-u) V01 + u V11)
其中 u、v 是小数部分,V 是像素值(对 R、G 和 B 重复)。