首页 > 解决方案 > 如何为 png 复制 Texture2d.LoadImage 以获得 RGB32 格式(现在获得 ARGB32)

问题描述

我正在尝试提高用于将 png 转换为灰度的代码的性能。

我通过 Json 加载图像,转换为纹理,然后在运行时通过每个像素进行灰度化并使用GetPixels32/SetPixels32. 对于我拥有的许多图像,内存使用量太高,所以我想使用更高效GetRawTextureData的 .

然而LoadImage,返回一个ARGB32 texture2d似乎搞砸了,然后在GetRawTextureDataRGB32)中使用。

这很令人困惑,因为在 Unity 2019.2 上带有 LoadImage 的 png 应该返回RGBA32,但对我来说,它返回的是ARGB32,这是 LoadImage 旧版 Unity 5.3 会返回的 - 不确定是否存在错误或文档错误。

Texture2D thisTexture = new Texture2D(1, 1, TextureFormat.RGBA32, false);
byte[] t = Convert.FromBase64String(imageString);//png image in string format
thisTexture.LoadImage(t);//Using Unity2019.2.2 result is ARGB32

当我将图像转换为灰度时,我得到一个淡黄色的图像,我认为这是GetRawTextureData因为RGB32LoadImage返回ARGB32

如何复制LoadImage获得RGB32的过程?

//convert texture
        graph = thisTexture;
        grayImg = new Texture2D(graph.width, graph.height, graph.format, false);

        Debug.Log("grayImg format " + grayImg.format + " graph format " + graph.format);
        Graphics.CopyTexture(graph, grayImg);
        var data = grayImg.GetRawTextureData<Color32>();

        int index = 0;
        Color32 pixel;
        for (int x = 0; x < grayImg.width; x++)
        {
            for (int y = 0; y < grayImg.height; y++)
            {
                pixel = data[index];
                int p = ((256 * 256 + pixel.r) * 256 + pixel.b) * 256 + pixel.g;
                int b = p % 256;
                p = Mathf.FloorToInt(p / 256);
                int g = p % 256;
                p = Mathf.FloorToInt(p / 256);
                int r = p % 256;
                byte l = (byte) ((pixel.r ) + pixel.g + pixel.b);
                Color32 c = new Color32(pixel.r, pixel.g, pixel.b, 1);
                data[index++] = c;
            }
        }
        // upload to the GPU
        grayImg.Apply(false);

使用 LoadRawTextureData 修改代码:

    Texture2D thisTexture = new Texture2D(1, 1, TextureFormat.RGBA32, false);
    byte[] t = Convert.FromBase64String(imageString);//png image in string format
    thisTexture.LoadRawTextureData(t);//results in RGBA32 (Note: using either thisTexture.LoadImage(t); or thisTexture.LoadRawTextureData(t); when using LoadRawTextureData to set the pixels on the grayscale, the texture continues to be yellowish.
    thisTexture.Apply();

标签: unity3dgputexturestexture2dloadimage

解决方案


这不是 GetRawTextureData 应该使用的方式 - 它重新调整 NativeArray 并且当与普通数组错误时非常慢。有关这方面的示例,请查看此 RawTextureDataProcessingExamples 存储库。特别是这个GrayscaleRGBA32Job文件:

using Unity.Mathematics;
using Unity.Collections;

[Unity.Burst.BurstCompile]
public struct GrayscaleRGBA32Job : Unity.Jobs.IJobParallelFor
{
    public NativeArray<RGBA32> data;
    void Unity.Jobs.IJobParallelFor.Execute ( int i )
    {
        var color = data[i];
        float product = math.mul( new float3{ x=color.R , y=color.G , z=color.B } , new float3{ x=0.3f , y=0.59f , z=0.11f } );
        byte b = (byte)product;
        data[i] = new RGBA32{ R=b , G=b , B=b , A=color.A };
    }
}

如果需要,可以在此处交换通道字节。这就是你申请这份工作的方式:

var rawdata = tex.GetRawTextureData<RGBA32>();
new GrayscaleRGBA32Job { data = tex.GetRawTextureData<RGBA32>() }
    .Schedule( rawdata.Length , tex.width ).Complete();
tex.Apply();

而已。基于此,您还可以编写一个将 RGBA32 rawData 作为输入并将其直接输出到灰度纹理的 R8 rawData 的作业(无需复制,并且内存占用更小)。


推荐阅读