【问题标题】:How replicate Texture2d.LoadImage for png to get RGB32 format (now getting ARGB32)如何为 png 复制 Texture2d.LoadImage 以获得 RGB32 格式(现在获得 ARGB32)
【发布时间】:2020-04-12 09:21:40
【问题描述】:

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

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

但是LoadImage 正在返回一个 ARGB32 texture2d,这似乎很混乱,然后在 GetRawTextureData (RGB32) 中继续使用。

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

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

当我将图像转换为灰度时,我得到一个黄色图像,我认为这是因为 GetRawTextureDataRGB32LoadImage 返回 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();

【问题讨论】:

  • 你的设备是什么?
  • 在独立的 windows 和 ios 上测试构建,目标是在 iOS 上构建用于移动设备(ios13 及更高版本)和 iPad
  • 您的代码缺少很多上下文。你在哪里定义changedPixels?为什么不使用 LoadRawTextureData 设置像素?
  • 对不起,没有 changedPixels ,我已经编辑了代码。不使用 changedPixels,因为这是使用 GetRawTextureData 的版本。我不知道 LoadRawTextureData 我现在要测试!
  • 你的图形 API 是什么?

标签: unity3d gpu textures texture2d loadimage


【解决方案1】:

这不是 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 的作业(无需复制,并且内存占用更小)。

【讨论】:

  • PS:没有RGB32这样的格式,但是有RGBA32和RGB24(有时也称为RGBA8、RGB8)。
  • 如果速度是您所追求的,那么请放弃从字符串、文本文件或其他任何内容中读取图像数据。使用原始二进制数据。
猜你喜欢
  • 1970-01-01
  • 2010-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多