将C++ OpenCV的图像Mat传送到Unity3D并且渲染显示

Unity3D中,我需要从C++的DLL中获取摄像头取得的图像数据(uchar *),并且用Rawimage显示出来。

程序包括C++的DLL接口部分和Unity3D C#的接口部分。

使用VS 2015建立一个空白的Visual C++ Win32控制台应用程序,使用.NET Framework 4.7.2,应用程序类型为DLL。

C++ CameraDll.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "Camera.h"

#define DLLExport __declspec(dllexport)

extern "C" {
DLLExport Camera* CreateCamera(int width, int height, int fps) {
Camera* obj = new Camera(width, height, fps);
return obj;
}

DLLExport void DestroyCamera(Camera* obj) {
delete obj;
obj = NULL;
}

DLLExport bool GetImage(Camera* obj, unsigned char *& data, int &size) {
return obj->GetImage(data, size);
}
}

C++ Camera.cpp:

1
2
3
4
5
6
7
8
...
bool Camera::GetImage(unsigned char*& rgb24_pixels, int& size) {
...
rgb24_pixels = img.data;
size = img.cols * img.rows * img.channels();
return true;
}
...

编译Release x64后,将dll文件放到Unity项目的Assets\Plugins文件夹中。Unity中建立Create Empty对象,添加一个脚本Camera.cs

C# Camera.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;

public class Camera : MonoBehaviour
{
[DllImport("Camera")]
private static extern IntPtr CreateCamera(int width, int height, int fps);

[DllImport("Camera")]
private static extern void DestroyCamera(IntPtr obj);

[DllImport("Camera")]
private static extern bool GetImage(IntPtr obj, ref IntPtr data, ref int size);

private int width_ = 640;
private int height_ = 480;
private int fps_ = 30;

private IntPtr Camera_ = IntPtr.Zero;
private IntPtr data_ = IntPtr.Zero;
private int size_ = 0;
private byte[] buffer_ = null;

private RawImage background_ = null;
private Texture2D tex_ = null;

// Start is called before the first frame update
void Start()
{
background_ = GameObject.FindWithTag("BackgroundImage").GetComponent<RawImage>();

Camera_ = CreateCamera(width_, height_, fps_);
}

void OnDestroy()
{
if (Camera_ != IntPtr.Zero)
{
DestroyCamera(Camera_);
Camera_ = IntPtr.Zero;
}
}

// Update is called once per frame
void Update()
{
if (Camera_ == IntPtr.Zero) return;

bool flag = GetImage(Camera_, ref data_, ref size_);

if (!flag || size_ <= 0) return;

if (buffer_ == null) {
buffer_ = new byte[size_];
}

if (tex_ == null) {
tex_ = new Texture2D(width_, height_, TextureFormat.RGB24, false, false);
}

System.Runtime.InteropServices.Marshal.Copy(data_, buffer_, 0, size_);
tex_.LoadRawTextureData(buffer_);
tex_.Apply();

background_.texture = tex_;

// byte[] bytes = tex_.EncodeToPNG();
// File.WriteAllBytes("Image.png", bytes);
}
}