Bilinear scarification algorithm

I wrote an algorithm for scaling an image using billing scalling, but it does not work as expected. I really can't seem to find the error in my code, but it produces the wrong output:

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;
    }

      

I'm generally interested. If I can view each channel together or do I need to split it (alpha at least)?

+3


source to share


2 answers


Channels must be separated. All of them. And then they are interpolated independently of each other.

Otherwise, they will interfere in odd ways, for example if you interpolate between pure white and pure black without separation, assuming that the interpolation is very fine-grained (about 24 pixels wide), to the black end you get in red (channel in low discharges), gradually decreasing until it overflows with a very dark green color, and then start again, but with a slightly more green color, repeating this pattern several times until finally it starts again, but with blue, mixed also. The coarser grainy interpolation essentially samples this strange rainbow at regular intervals.



Interpolating the channels individually will cause all channels to grow at the same rate (and not going back to zero periodically) towards the white end, giving the expected gray gradient.

+2


source


If the data is RGBA values ​​(as indicated by harold), then the corresponding component for the next pixel is not in the next byte, it is four bytes, and the string width is not w

bytes, but w * 4

bytes.

The code will do this:



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;
}

      

+1


source







All Articles