将 24 位 BGR 图像从内存加载到 ID2D1Bitmap1 的最佳方法

Best way to load 24-bit BGR image from memory to ID2D1Bitmap1

我在内存中有一个 BGR 24 位图像作为连续缓冲区(用 cv::Mat 表示,以防它有任何帮助)。我想将它加载到 ID2D1Bitmap1 位图以进行 2D 渲染。我有以下工作代码(此处显示伪代码):

IWICImagingFactory::CreateBitmapFromMemory(GUID_WICPixelFormat24bppBGR);
IWICFormatConverter::Initialize(GUID_WICPixelFormat32bppRGB);
ID2D1DeviceContext::CreateBitmapFromWicBitmap;

这工作正常,主要问题是它花费的时间:20-40 毫秒,这对我的应用程序来说太长了。我正在寻找优化流程的方法。

我可能可以通过这样做一次来节省 ID2D1Bitmap1 的创建时间,然后使用 CopyFromMemory 从内存中加载转换后的图像,但转换本身仍然需要大量时间的时间。一种方法是将原始 BGR 缓冲区加载到 GPU 内存,并在 GPU 本身上将其转换为 native RGBA 格式,但我不知道如何开始。

你的第二个想法正是你应该去的方向。创建 ID2D1Bitmap(s) 一次,转换缓冲区(下面有更多内容),然后使用 CopyFromMemory。我在一个应用程序中做了一些非常相似的事情,该应用程序提供了连接的网络摄像头的预览(可能具有多种格式之一)。有些相机会以 MJPEG、YUY2 等格式传送图像。

该应用程序使用 MediaFoundationIMFTransform 来转换缓冲区。本例中的 IMFTransformCLSID_CColorConvertDMO 的一个实例(尽可能使用 SIMD registers/instructions)。然而,在完成之前,我测试了我自己的转换代码(这是 CPU 绑定的,并且执行得一般),以及另一个使用 HLSLDirectCompute 的解决方案(执行得很好,但只处理一种格式)。最后我选择了 CLSID_CColorConvertDMO 来处理各种类型的输入,但是如果你只有一种已知类型,你可以选择使用 HLSL 解决方案(尽管它会导致你必须编写转换码,并设置数据的'views')。

但是,如果您选择 MediaFoundation 路线,则可以使用 IMFTransform 而无需图表的所有其余部分(源、汇等)。创建 CLSID_CColorConvertDMO 实例并设置输入和输出类型(格式、帧大小等)后,创建一个 IMFSample (using MFCreateSample), and an IMFMediaBuffer (using MFCreateMemoryBuffer) to the sample (using IMFSample::AddBuffer), then all that is necessary is to call ProcessInput and ProcessOutput 来转换缓冲区(预先创建所有项目)。这听起来可能很多,但如果操作正确,您的 cpu 利用率不会产生明显的影响,并且您将实现您正在寻找的性能,即使对于通常以 60+ FPS 提供大帧的采集卡也是如此(过去使用过 DataPath 和 Blackmagic 采集卡)。

祝你好运。我相信你会粉碎它。