You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优化Canvas鱼眼算法,降低中心区域的过度畸变?

鱼眼放大镜算法中心畸变优化方案

问题背景

我希望实现一个类似屏幕放大镜效果的简易鱼眼算法,基于Canvas的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);

问题原因

原代码中使用Math.sin(((dist / SIZE) * Math.PI) / 2)作为像素偏移的因子,该函数在dist趋近于0(中心区域)时导数为1,意味着像素偏移量会从0突然开始快速增加,导致中心附近的畸变变化剧烈,视觉效果突兀。

优化方案

替换原有的正弦因子为变化率更平缓的缓动函数,这类函数在dist=0时的导数为0,偏移量随距离中心的远近缓慢提升,从而让中心区域的畸变更平滑。以下是几种可行的实现:

方案1:二次缓出函数

该函数让偏移量先慢后快,中心区域过渡自然:

if (dist <= SIZE) {
    var t = dist / SIZE;
    // 二次缓出因子:t*(2-t)
    var factor = t * (2 - t);
    var x2 = Math.round(mouseX - dx * factor);
    var y2 = Math.round(mouseY - dy * factor);
    var i2 = (y2 * frame.width + x2) * 4;
}

方案2:三次平滑缓动函数

该函数的变化率全程平滑,无突兀拐点:

if (dist <= SIZE) {
    var t = dist / SIZE;
    // 三次缓动因子:3t² - 2t³
    var factor = 3 * t * t - 2 * t * t * t;
    var x2 = Math.round(mouseX - dx * factor);
    var y2 = Math.round(mouseY - dy * factor);
    var i2 = (y2 * frame.width + x2) * 4;
}

方案3:余弦补函数

相比原正弦函数,该函数在中心区域的变化更平缓:

if (dist <= SIZE) {
    // 余弦补因子:1 - cos((t)*π/2)
    var factor = 1 - Math.cos((dist / SIZE) * Math.PI / 2);
    var x2 = Math.round(mouseX - dx * factor);
    var y2 = Math.round(mouseY - dy * factor);
    var i2 = (y2 * frame.width + x2) * 4;
}

效果说明

以上方案均能让中心区域的畸变从0开始缓慢增加,避免了原算法的突变问题,你可以根据需求调整SIZE参数,或者尝试不同的缓动因子来达到理想的放大镜效果。

内容的提问来源于stack exchange,提问作者Max Frai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 22:45:37