【问题标题】:Unity - extracting camera pixel array is incredibly slowUnity - 提取相机像素阵列非常慢
【发布时间】:2020-07-12 17:10:37
【问题描述】:

我使用下面的代码行在每一帧从相机中提取像素数组,将其保存为 jpg,然后在 jpg 上运行 python 进程。虽然它有效,但速度非常慢。瓶颈似乎是统一读取像素。 python进程本身只持续0.02秒。

谁能建议我可以加快这个过程的相对简单的方法?

我见过 this ,但它太高级了,我无法理解如何使其适应我的用例。

public override void Initialize()
{
    renderTexture = new RenderTexture(84, 84, 24);
    rawByteData = new byte[84 * 84 * bytesPerPixel];
    texture2D = new Texture2D(84, 84, TextureFormat.RGB24, false);
    rect = new Rect(0, 0, 84, 84);
    cam.targetTexture = renderTexture;

}
private List<float> run_cmd()
{
    // Setup a camera, texture and render texture
    cam.targetTexture = renderTexture;
    cam.Render();
    // Read pixels to texture
    RenderTexture.active = renderTexture;
    texture2D.ReadPixels(rect, 0, 0);
    rawByteData = ImageConversion.EncodeToJPG(texture2D);
    // Assign random temporary filename to jpg
    string fileName = "/media/home/tmp/" + Guid.NewGuid().ToString() + ".jpg";
    File.WriteAllBytes(fileName, rawByteData); // Requires System.IO

     // Start Python process
     ProcessStartInfo start = new ProcessStartInfo();
     start.FileName = "/media/home/path/to/python/exe";
     start.Arguments = string.Format(
        "/media/home/path/to/pythonfile.py photo {0}", fileName);
     start.UseShellExecute = false;
     start.RedirectStandardOutput = true;
     start.RedirectStandardError = true;
     string stdout;
     using(Process process = Process.Start(start))
     {
         using(StreamReader reader = process.StandardOutput)
         {
             stdout = reader.ReadToEnd();
         }
     }

    string[] tokens = stdout.Split(',');
    List<float> result = tokens.Select(x => float.Parse(x)).ToList();
    System.IO.File.Delete(fileName);

    return result;


}

【问题讨论】:

  • 您在答案中附加的 Medium 示例非常简单,您使用过吗?
  • 他们附上的例子是未优化的版本,非常慢。然后他们继续解释如何提高性能,但没有提供优化版本的源代码......

标签: python c# unity3d ml-agent


【解决方案1】:

在 Unity 2018.1 中添加了一个用于从 GPU 异步读取数据的新系统 - https://docs.unity3d.com/ScriptReference/Rendering.AsyncGPUReadback.html,在这个不需要使用相机来获取纹理数组的情况下,我编写了一个简单的示例,它运行良好且速度非常快:

using System.Collections;
using System.IO;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;

public class CameraTextureTest : MonoBehaviour
{
    private GraphicsFormat format;
    
    private int frameIndex = 0;
    
    IEnumerator Start()
    {
        yield return new WaitForSeconds(1);

        while (true)
        {
            yield return new WaitForSeconds(0.032f);
            yield return new WaitForEndOfFrame();

            var rt = RenderTexture.GetTemporary(Screen.width, Screen.height, 32);

            format = rt.graphicsFormat;

            ScreenCapture.CaptureScreenshotIntoRenderTexture(rt);
            
            AsyncGPUReadback.Request(rt, 0, TextureFormat.RGBA32, OnCompleteReadback);
            
            RenderTexture.ReleaseTemporary(rt);
        }
    }


    void OnCompleteReadback(AsyncGPUReadbackRequest request)
    {
        if (request.hasError)
        {
            Debug.Log("GPU readback error detected.");
            return;
        }

        byte[] array = request.GetData<byte>().ToArray();
        
        Task.Run(() =>
        {
            File.WriteAllBytes($"D:/Screenshots/Screenshot{frameIndex}.png",ImageConversion.EncodeArrayToPNG(array, format, (uint) Screen.width, (uint) Screen.height));
        });

        frameIndex++;
    }
}

您可以根据您的任务调整此示例。

【讨论】:

    猜你喜欢
    • 2018-06-08
    • 1970-01-01
    • 2022-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 2020-06-07
    相关资源
    最近更新 更多