首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何避免drawImage()星爆伪像?

如何避免drawImage()星爆伪像?
EN

Stack Overflow用户
提问于 2016-02-02 02:48:05
回答 1查看 194关注 0票数 2

1.原问题:

我正在做一个画布动画“缩放”效果,它产生了一些恼人的视觉效果。这个简化的示例显示了255帧之后的输出。在每一帧中,会发生两件事:(1) drawArc()在画布的中心创建一个彩色(灰色)磁盘;(2) imageDraw()以稍微放大的比例重新绘制画布。我期望看到一个平滑的径向梯度从中心向外扩展。相反,这是我所看到的:

让我头疼的是(a)沿着垂直轴和水平轴(在较小程度上,在对角线上)的明亮的“星暴”和(b)模糊的菱形图案。

我想这是drawImage()缩放算法的某种伪像。我试着调整了所有的参数(deltastrokeWidth,圆弧半径),但总有一些版本的星暴效应。有什么建议如何避免--或者至少减少--这种效应?

下面是我的代码:

代码语言:javascript
复制
var cv = document.getElementById("testCanvas");
var ctx = cv.getContext('2d');
var cvHeight = cv.height;
var cvWidth = cv.width;
for (var j=0;j<255;j++) {
    var delta = 4;

    // redraw the canvas, enlarged by delta pixels
    ctx.drawImage(cv, 0, 0, cvWidth, cvHeight, 
        -delta/2, -delta/2, cvWidth+delta, cvHeight+delta);

    // draw a new circle at the center, in a different color
    ctx.beginPath();
    ctx.strokeStyle = "rgb("+ j + "," + j + "," + j +")";
    ctx.strokeWidth = 10;
    ctx.arc(cvWidth/2, cvHeight/2, 10, 0, Math.PI*2.0);    
    ctx.stroke();   
}

这是the JSFiddle

2.进一步细化

正如@Igor Raush恰如其分地观察到的那样,我给出的示例图像可以使用createRadialGradient()更好地渲染(无星暴)。但是我的示例代码过于简单且具有误导性:我的目标不是生成径向颜色渐变,而是通过连续调用imageDraw()来放大画布来创建缩放动画效果。在上面的例子中,一个静态的白色圆盘被放置在画布的中心。在我的实际应用程序中,每个帧的画布中心都会放置一个新图像。问题是,无论什么类型的图像最初放置在画布的中心,这些恼人的星暴模式都会在某种程度上出现。

这里有一个使用随机数据和真实动画的更好的例子。(为了简单起见,我在这里使用随机数据。我的应用程序中的实际数据不是随机的,但效果是相同的。)在每个帧中,在画布的中心绘制一个由随机着色的点组成的环(ctx.arc());然后,imageDraw()略微扩展画布。

这是JS Fiddle,代码如下:

代码语言:javascript
复制
var cv = document.getElementById("testCanvas");
var ctx = cv.getContext('2d');
var cvHeight = cv.height;
var cvWidth = cv.width;
var delta = 10; // higher = faster "expansion" of the canvas
var data = new Array(100);

setInterval( function() { 
    FetchNewData(data); // fill the array with new data
    DrawTheRing(cv,data); // draw the data around a ring, as shades of gray, centered on the canvas
    ctx.drawImage(cv, 0, 0, cvWidth, cvHeight, -delta/2, -delta/2, cvWidth+delta, cvHeight+delta); // expand the canvas
} , 10);


// Load up the array with random data
function FetchNewData(data) {
    var nSamples = data.length;
    for (var k=0; k< nSamples; k++) {
        data[k] = Math.floor((Math.random() * 255));
    }
}

// draw a ring, centered on the canvas, containing the grayscale data
function DrawTheRing(cv,data) {
    var radius = 10;
    var thickness = 10;
    var ctx = cv.getContext('2d');
    var angle = 0;
    var dAngle = Math.PI*2.0/data.length;
    for ( var k = 0; k < data.length; k++) {
        var value = data[k];
        ctx.beginPath();
        ctx.lineWidth = thickness;
        ctx.strokeStyle = "rgb("+ value + "," + value + "," + value +")";    // a shade of gray
        ctx.arc(cvWidth/2, cvHeight/2, radius, angle, angle+dAngle);    
        ctx.stroke();    
        angle += dAngle;
    }
}

以下是它的运行快照:

关于如何避免在垂直轴、水平轴和对角线上出现虚假的锐利线条,有什么想法吗?有没有更好的方法来实现这种缩放效果?

EN

回答 1

Stack Overflow用户

发布于 2016-02-02 04:17:29

这些不完美确实是由于缩放造成的。一旦在画布上绘制路径,路径信息就会丢失,因此您正在调整图像的栅格化版本的大小。这就是为什么你的圆最终看起来像多边形。

您可以改用ctx.createRadialGradient,为色标设置动画,然后在每一帧重新绘制画布。

代码语言:javascript
复制
var s = 0.99;
var x = cvWidth / 2,
    y = cvHeight / 2,
    r = cvWidth / 2;

// generate gradient
var gradient = ctx.createRadialGradient(x, y, r, x, y, 0);
gradient.addColorStop(0, 'black');
gradient.addColorStop(s, 'black');
gradient.addColorStop(1, 'white');

Here就是一个例子。您可以使用内圆半径和控制颜色停止的计时功能来实现您想要的结果。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35138002

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档