mipmapping产生错误的结果

时间:2013-09-16 09:26:44

标签: c# image mipmaps

我正在尝试生成图像的mipmap。像素存储为byte [],格式为{r,g,b,a,r,g,b,a,r,g,b,a ...}

这样做的目的是让图像中的每组四个像素找到这四个像素的平均值,然后将其放入新图像中。

为示例纹理创建所有mipmap的结果如下:http://imgur.com/KdEEzAw

如果有一种方法可以在不使用我自己的算法的情况下创建mipmap,并且没有directx或任何东西(我没有使用mipmaps进行渲染,我将它们保存到文件中),那将是不错的

public static byte[] mipmap(byte[] inPixels, int width, int height)
{
    // add one to width and height incase they are 1
    byte[] outPixels = new byte[((width + 1) / 2) * ((height + 1) / 2) * 4];
    for (int y = 0; y < height; y += 2)
    {
        for (int x = 0; x < width; x += 2)
        {
            // get the four red values
            int[] r = new int[4];
            r[0] = (int)inPixels[x + y * width + 0]; // top left
            r[1] = (int)inPixels[(x + 1) + y * width + 0]; // top right
            r[2] = (int)inPixels[(x + 1) + (y + 1) * width + 0]; // bottom right
            r[3] = (int)inPixels[x + (y + 1) * width + 0]; // bottom left

            // get the four green values
            int[] g = new int[4];
            g[0] = (int)inPixels[x + y * width + 1]; // top left
            g[1] = (int)inPixels[(x + 1) + y * width + 1]; // top right
            g[2] = (int)inPixels[(x + 1) + (y + 1) * width + 1]; // bottom right
            g[3] = (int)inPixels[x + (y + 1) * width + 1]; // bottom left

            // get the four blue values
            int[] b = new int[4];
            b[0] = (int)inPixels[x + y * width + 2]; // top left
            b[1] = (int)inPixels[(x + 1) + y * width + 2]; // top right
            b[2] = (int)inPixels[(x + 1) + (y + 1) * width + 2]; // bottom right
            b[3] = (int)inPixels[x + (y + 1) * width + 2]; // bottom left

            // get the four alpha values
            int[] a = new int[4];
            a[0] = (int)inPixels[x + y * width + 3]; // top left
            a[1] = (int)inPixels[(x + 1) + y * width + 3]; // top right
            a[2] = (int)inPixels[(x + 1) + (y + 1) * width + 3]; // bottom right
            a[3] = (int)inPixels[x + (y + 1) * width + 3]; // bottom left

            // the index in the new image, we divide by 2 because the image is half the size of the original image
            int index = (x + y * width) / 2;
            outPixels[index + 0] = (byte)((r[0] + r[1] + r[2] + r[3]) / 4);
            outPixels[index + 1] = (byte)((g[0] + g[1] + g[2] + g[3]) / 4);
            outPixels[index + 2] = (byte)((b[0] + b[1] + b[2] + b[3]) / 4);
            outPixels[index + 3] = (byte)((a[0] + a[1] + a[2] + a[3]) / 4);
        }
    }
    return outPixels;
}

1 个答案:

答案 0 :(得分:0)

我认为问题在于:

inPixels[x + y * width + 0]

通常,当一个数组元素是一个像素时,运行正确,只有一个元素是一个像素的一个通道。所以每个像素开始一个(x +(y *宽度))* 4 所以它应该是这样的:

inPixels[((x + y * width) * 4) + 0]

我写了一些优化代码,也许你会得到一些额外的想法,但我没有测试它:

public static byte[] mipmap(byte[] inPixels, int width, int height)
{
    // add one to width and height incase they are 0
    byte[] outPixels = new byte[((width / 2) * (height / 2)) * 4];

    // the offsets of the neighbor pixels (with *4 for the channel)
    // this will automatically select a channel of a pixel one line down.
    int[] neighborOffsets = new int[] { 0 * 4, 1 * 4, width * 4, (width + 1) * 4 };

    // an 'offset for output buffer'
    int outputOffset = 0;

    // an 'offset for input buffer'
    int inputOffset = 0;

    for (int y = 0; y < height / 2; y++)
    {
        for (int x = 0; x < width / 2; x++)
        {

            // calculate the average of each channel
            for (int channelIndex = 0; channelIndex < 4; channelIndex++)
            {
                int totalValue = 0;

                for (int offset = 0; offset < 4; offset++)
                    totalValue = (int)inPixels[inputOffset + neighborOffsets[offset] + channelIndex];

                // write it to the ouput buffer and increase the offset.
                outPixels[outputOffset++] = (byte)(totalValue / 4);

            }
            // set the input offset on the next pixel. The next pixel is current + 2.
            inputOffset += 2 * 4; // *4 for the channelcount (*4 will be optimized by the compiler)
        }
        inputOffset += width * 4; // skip an extra line. *4 for the channelcount (*4 will be optimized by the compiler)
    }

    return outPixels;
}

它可能有一些小错误,但它可能运行速度快4倍。尽量避免乘法时的冗余。