如何优化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
相关产品推荐
相关产品推荐

