双线性缩放算法的奇怪效果

3

我编写了一个使用双线性插值方法缩放图像的算法,但它并没有按预期工作。我真的找不到我的代码中的任何错误,但它正在产生错误的输出:

enter image description here

    Process(context: ImageData): ImageData {
        var imageData = context;

        var w = imageData.width;
        var h = imageData.height;

        var small = new Uint32Array((<any>imageData.data).buffer);
        var big = new Uint32Array(small.length * (this.factor * this.factor));

        var w2 = this.factor * imageData.width;
        var h2 = this.factor * imageData.height;

        var x_ratio = ((w) / w2);
        var y_ratio = ((h) / h2);

        for (var i = 0, f = h2; i < f; ++i) {

            var py_a = (i * y_ratio);
            var py = py_a | 0;
            var py_t = py_a - py;

            for (var j = 0, k = w2; j < k; ++j) {
                var px_a = (j * x_ratio);
                var px =  px_a | 0;
                var index = ((py * w) + px) | 0;

                var px_t = px_a - px;

                var fy1 = small[index] + (small[index + 1] - small[index]) * px_t;
                var fy2 = small[index + w] + (small[index + w + 1] - small[index + w]) * px_t;

                var tmp = fy1 + (fy2 - fy1) * py_t;

                big[i * w2 + j] = tmp;
            }
        }

        var ar = new Uint8ClampedArray(big.buffer);
        var newImage = new ImageData(ar, w2, h2);

        return newImage;
    }

我想知道是否可以将每个通道一起处理,还是应该分开处理(至少alpha通道)?


图像数据代表什么?您所拥有的内容适用于灰度图像,其中每个字节表示像素的亮度。如果每个字节表示调色板中的索引而不是亮度级别,则可以解释您获取到的模式。在这种情况下,当您读取每个值时,您需要将其转换为亮度级别,并在写入时将其转换为调色板索引。 - Guffa
@Guffa 它进入了一个ImageData,这使它成为RGBA像素。 - harold
离题:边缘上的图像似乎值可能超出了它们的范围(也许是每个通道),但我真的很喜欢它的外观 :) - George Profenza
2个回答

2
所有通道必须分开。并且独立地进行插值处理。
否则,它们会以奇怪的方式干扰彼此。例如,如果您在未分开通道的情况下在纯白和纯黑之间进行插值,假设插值非常细粒度(大约224像素宽),向黑色端移动,您会得到红色(最低位通道),逐渐变得更红,直到溢出为非常深的绿色,然后再次开始,但混入了略微更多的绿色,并重复这种模式几次,直到最后再次开始,但也混入了蓝色。更粗糙的插值本质上在固定间隔内对那个奇怪的彩虹进行采样。
分别插值通道会使所有通道朝着白色端以相同的速度增加(并且不会周期性地返回零),从而产生灰色渐变,这是预期的。

1
如果数据是RGBA值(如Harold所示),则下一个像素的相应分量不在下一个字节中,而是相隔四个字节,一行的宽度不是w字节,而是w * 4字节。
代码如下:
Process(context: ImageData): ImageData {
    var imageData = context;

    var w = imageData.width;
    var h = imageData.height;

    var small = new Uint8Array((<any>imageData.data).buffer);
    var big = new Uint8Array(small.length * (this.factor * this.factor));

    var w2 = this.factor * imageData.width;
    var h2 = this.factor * imageData.height;

    var x_ratio = ((w) / w2);
    var y_ratio = ((h) / h2);

    for (var i = 0, f = h2; i < f; ++i) {

        var py_a = (i * y_ratio);
        var py = py_a | 0;
        var py_t = py_a - py;

        for (var j = 0, k = w2 * 4; j < k; ++j) {
            var px_a = (j * x_ratio);
            var px =  px_a | 0;
            var index = ((py * w * 4) + px) | 0;

            var px_t = px_a - px;

            var fy1 = small[index] + (small[index + 4] - small[index]) * px_t;
            var fy2 = small[index + w * 4] + (small[index + w * 4 + 4] - small[index + w * 4]) * px_t;

            var tmp = fy1 + (fy2 - fy1) * py_t;

            big[i * w2 * 4 + j] = tmp;
        }
    }

    var newImage = new ImageData(big, w2, h2);

    return newImage;
}

好的,它是rgba,但是在32位整数中打包,如果我造成了混淆,我很抱歉。 - harold
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Guffa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接