【问题标题】:Smooth jagged pixels平滑锯齿状像素
【发布时间】:2018-02-22 15:23:18
【问题描述】:

我使用以下算法在画布上创建了捏合滤镜/效果:

// iterate pixels
for (var i = 0; i < originalPixels.data.length; i+= 4) {

    // calculate a pixel's position, distance, and angle
    var pixel = new Pixel(affectedPixels, i, origin);

    // check if the pixel is in the effect area
    if (pixel.dist < effectRadius) {

        // initial method (flawed)
        // iterate original pixels and calculate the new position of the current pixel in the affected pixels
        if (method.value == "org2aff") {

            var targetDist = ( pixel.dist - (1 - pixel.dist / effectRadius) * (effectStrength * effectRadius) ).clamp(0, effectRadius);
            var targetPos  = calcPos(origin, pixel.angle, targetDist);

            setPixel(affectedPixels, targetPos.x, targetPos.y, getPixel(originalPixels, pixel.pos.x, pixel.pos.y));

        } else {

            // alternative method (better)
            // iterate affected pixels and calculate the original position of the current pixel in the original pixels
            var originalDist = (pixel.dist + (effectStrength * effectRadius)) / (1 + effectStrength);
            var originalPos  = calcPos(origin, pixel.angle, originalDist);

            setPixel(affectedPixels, pixel.pos.x, pixel.pos.y, getPixel(originalPixels, originalPos.x, originalPos.y));

        }

    } else {
        // copy unaffected pixels from original to new image
        setPixel(affectedPixels, pixel.pos.x, pixel.pos.y, getPixel(originalPixels, pixel.pos.x, pixel.pos.y));
    }
}

我为此付出了很多努力,我对结果感到非常满意。不过,我有一个小问题;锯齿状像素。比较 JS 捏和 Gimp 的:

我不知道我错过了什么。我需要在实际过滤器之后应用另一个过滤器吗?还是我的算法完全错误?


我无法在此处添加完整代码(作为 SO sn-p),因为它包含 4 个 base64 图像/纹理(总共 65k 个字符)。取而代之的是JSFiddle

【问题讨论】:

  • 看起来method2是你对your codereview question的Kruga想法的实现——method2和gimp最大的区别是gimp的图像充满了抗锯齿。我想知道,如果方法 2 是针对每个目标像素计算源像素的加权平均值,您能否相应地改变用于目标像素的灰色阴影?这应该接近 gimp 结果。
  • 正确。我已经看到了方法 2 在旋转中的作用,并在我的代码中试了一下。正如您和亚历克斯指出的那样,我认为我还需要应用第二个过滤器/插值/抗锯齿,或任何所谓的。首先,我将对这个主题进行广泛的研究。

标签: javascript image-processing canvas pixel-manipulation


【解决方案1】:

清理结果的一种方法是超级采样。这是一个简单的例子:https://jsfiddle.net/Lawmo4q8/

基本上,不是为单个像素计算单个值,而是在像素内/周围获取多个值样本...

let color =
    calcColor(x - 0.25, y - 0.25) + calcColor(x + 0.25, y - 0.25) +
    calcColor(x - 0.25, y + 0.25) + calcColor(x + 0.25, y + 0.25);

...并以某种方式合并结果。

color /= 4;

【讨论】:

  • 感谢您的建议和演示,但我认为没有那么简单。我正在尝试实施您的方法,但失败了。我认为您正在使用calcColor 创建该波形,并且在采样时,您使用的是相同的功能。就我而言,我需要能够使用已经创建的形状,即imageData(像素)。我创建了一个demo,但我的结果不如你的顺利。我做错了什么?
  • 真的就是这么简单。如果你有一个函数可以将输出图像中的一个像素映射到输入图像中的一个像素,那么你所要做的就是为每个输出像素采样多个输入像素。
  • 我认为我已经在这样做了,但它并没有真正起作用。我肯定错过了什么。我可以要求您检查我提供的演示吗?我写的很简单,所以我怀疑你会很难注意到这个问题。如果你比较结果,你就会明白我在说什么。
  • 它工作得很好,正如您的演示所示。您可以通过使用加权内核(即高斯,jsfiddle.net/8oLv6wkh/5)并增加内核的大小来获得稍微好一点的结果,但这与从有限分辨率采样时获得的效果一样好。如果您知道只需处理 2 种颜色,您还可以做其他事情,但在我看来,您正在寻找一种通用的方法。
猜你喜欢
  • 2019-04-30
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多