【问题标题】:Bilinear scalling algorithm weird effects双线性缩放算法奇怪的效果
【发布时间】:2015-10-24 22:59:32
【问题描述】:

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

    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 它进入 ImageData,使其成为 RGBA 像素
  • 离题:边缘的伪像看起来值可能超出了它们的范围(可能是每个通道),但我真的很喜欢它的外观:)

标签: javascript algorithm image-processing typescript


【解决方案1】:

频道必须分开。他们都是。然后相互独立地插值。

否则它们会以奇怪的方式干扰,例如,如果您在纯白色和纯黑色之间插值而不分裂,假设插值非常细粒度(大约 224 像素宽),朝向黑色结束你会得到红色(最低位的通道),逐渐变红直到溢出到非常深的绿色,然后重新开始,但混合了稍微更多的绿色,重复这个模式几次,直到最后它重新开始,但是也混入了蓝色。更粗粒度的插值本质上是定期对奇怪的彩虹进行采样。

分别对通道进行插值将使所有通道以相同的速率(并且不会周期性地回到零)向白色端增加,从而产生灰色渐变,这是预期的。

【讨论】:

    【解决方案2】:

    如果数据是 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:对,代码从图像数据创建 32 位整数。如果它创建了 8 位整数,那么单独使用平面会很容易。
    猜你喜欢
    • 2011-05-16
    • 1970-01-01
    • 2011-08-09
    • 1970-01-01
    • 2015-11-14
    • 2017-06-07
    • 2021-07-20
    • 2014-06-26
    • 1970-01-01
    相关资源
    最近更新 更多