gpt4 book ai didi

c# - 将 OpenCV Mat 转换为 Texture2D?

转载 作者:可可西里 更新时间:2023-11-01 18:29:03 35 4
gpt4 key购买 nike

元上下文:

我目前正在开发一款使用 opencv 代替普通输入(键盘、鼠标等)的游戏。我通过 DllImports 在 C++ 中使用 Unity3D 的 C# 脚本和 opencv。我的目标是在我的游戏中创建一个来自 opencv 的图像。

代码上下文:

正如通常在 OpenCV 中所做的那样,我使用 Mat 来表示我的图像。这是我导出图像字节的方式:

cv::Mat _currentFrame;

...

extern "C" byte * EXPORT GetRawImage()
{
return _currentFrame.data;
}

这就是我从 C# 导入的方式:

[DllImport ("ImageInputInterface")]
private static extern IntPtr GetRawImage ();

...

public static void GetRawImageBytes (ref byte[] result, int arrayLength) {
IntPtr a = GetRawImage ();
Marshal.Copy(a, result, 0, arrayLength);
FreeBuffer(a);
}

根据我对 OpenCV 的理解,我希望字节数组在 uchar 指针中序列化时以这种方式构造:

b1, g1, r1, b2, g2, r2, ...

我正在使用以下方法将此 BGR 数组转换为 RGB 数组:

public static void BGR2RGB(ref byte[] buffer) {
byte swap;
for (int i = 0; i < buffer.Length; i = i + 3) {
swap = buffer[i];
buffer[i] = buffer[i + 2];
buffer[i + 2] = swap;
}
}

最后,我使用 Unity 的 LoadRawTextureData 将字节加载到纹理:

this.tex = new Texture2D(
ImageInputInterface.GetImageWidth(),
ImageInputInterface.GetImageHeight(),
TextureFormat.RGB24,
false
);

...

ImageInputInterface.GetRawImageBytes(ref ret, ret.Length);
ImageInputInterface.BGR2RGB(ref ret);
tex.LoadRawTextureData(ret);
tex.Apply();

结果:

最终图像似乎以某种方式散落,它类似于一些形状,但它似乎也是三倍的形状。这是我在镜头前牵着我的手:

[我,我的手和相机]

做了一些测试,我得出结论,我正确地解码了 channel ,因为使用我的手机发出 RGB 光,我可以再现现实世界的颜色:

[红色测试]

[蓝色测试]

[绿色测试]

图像中还有一些奇怪的线条:

[诡异线条]

还有我的脸可以比较这些图像:

[我在镜头前的脸]

问题:

既然我能够正确解码颜色 channel ,那么我在解码 OpenCV 数组时假设错了什么?是我不知道 Unity 的 LoadRawTextureData 是如何工作的,还是我以错误的方式解码了一些东西?

OpenCV Mat.data 数组的结构是怎样的?

更新

感谢@Programmer,他的解决方案就像魔术一样奏效。

[我快乐]

我稍微改变了他的剧本,不需要做一些事情。在我的例子中,我需要使用 BGR2RGBA,而不是 RGB2RGBA:

extern "C" void EXPORT GetRawImage( byte *data, int width, int height )
{
cv::Mat resizedMat( height, width, _currentFrame.type() );
cv::resize( _currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC );

cv::Mat argbImg;
cv::cvtColor( resizedMat, argbImg, CV_BGR2RGBA );
std::memcpy( data, argbImg.data, argbImg.total() * argbImg.elemSize() );
}

最佳答案

使用 SetPixels32 而不是 LoadRawTextureData。不要从 C++ 返回数组数据,而是从 C# 返回数组数据。创建 Color32 数组并使用 GCHandle.Alloc 将其固定在 c# 中,将固定的 Color32 数组的地址发送到 C++,使用 cv::resize调整 cv::Mat 的大小以匹配从 C# 发送的像素大小。您必须执行此步骤,否则会出现一些错误或问题。

最后,将 cv::MatRGB 转换为 ARGB 然后使用 std::memcpy 更新来自 C++ 的数组。然后可以使用 SetPixels32 函数将更新后的 Color32 数组加载到 Texture2D 中。我就是这样做的,它一直在为我工作,没有任何问题。可能还有其他更好的方法,但我从未找到过。

C++:

cv::Mat _currentFrame;

void GetRawImageBytes(unsigned char* data, int width, int height)
{
//Resize Mat to match the array passed to it from C#
cv::Mat resizedMat(height, width, _currentFrame.type());
cv::resize(_currentFrame, resizedMat, resizedMat.size(), cv::INTER_CUBIC);

//You may not need this line. Depends on what you are doing
cv::imshow("Nicolas", resizedMat);

//Convert from RGB to ARGB
cv::Mat argb_img;
cv::cvtColor(resizedMat, argb_img, CV_RGB2BGRA);
std::vector<cv::Mat> bgra;
cv::split(argb_img, bgra);
std::swap(bgra[0], bgra[3]);
std::swap(bgra[1], bgra[2]);
std::memcpy(data, argb_img.data, argb_img.total() * argb_img.elemSize());
}

C#:

使用 Renderer 附加到任何游戏对象,您应该会看到 cv::Mat 在该对象上每一帧显示和更新。如果混淆,代码将被注释:

using System;
using System.Runtime.InteropServices;
using UnityEngine;

public class Test : MonoBehaviour
{
[DllImport("ImageInputInterface")]
private static extern void GetRawImageBytes(IntPtr data, int width, int height);

private Texture2D tex;
private Color32[] pixel32;

private GCHandle pixelHandle;
private IntPtr pixelPtr;

void Start()
{
InitTexture();
gameObject.GetComponent<Renderer>().material.mainTexture = tex;
}


void Update()
{
MatToTexture2D();
}


void InitTexture()
{
tex = new Texture2D(512, 512, TextureFormat.ARGB32, false);
pixel32 = tex.GetPixels32();
//Pin pixel32 array
pixelHandle = GCHandle.Alloc(pixel32, GCHandleType.Pinned);
//Get the pinned address
pixelPtr = pixelHandle.AddrOfPinnedObject();
}

void MatToTexture2D()
{
//Convert Mat to Texture2D
GetRawImageBytes(pixelPtr, tex.width, tex.height);
//Update the Texture2D with array updated in C++
tex.SetPixels32(pixel32);
tex.Apply();
}

void OnApplicationQuit()
{
//Free handle
pixelHandle.Free();
}
}

关于c# - 将 OpenCV Mat 转换为 Texture2D?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49482647/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com