「boostの共有メモリで画像を受け渡しする」でも紹介したけど, 共有メモリを使ってプログラムを2つに分けるとライブラリの依存関係やバージョン管理がシンプルになる場合がある. 今回は,C++のライブラリのみが提供されているカメラの画像をUnityのプログラムに送信するために, C++のプログラムからC#のプログラムに画像を送信するサンプルコードを掲載. 送信側を起動してから受信側を起動すると正常に動作する. 画像サイズは640$\times$480で,BGRAの順にデータが格納されているとする.ただし,これはWindowsのAPIを用いているためboostを用いたものと違ってWindows限定.
送信側(C++)
#include <windows.h> #include <string> #include <opencv2/opencv.hpp> int main(int argc, char* argv[]) { std:: string MemoryName = "COLOR_IMAGE640x480"; int w = 640; int h = 480; int size = w * h * 4; HANDLE memory = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, MemoryName.c_str()); uchar * data = (uchar *)MapViewOfFile(memory, FILE_MAP_ALL_ACCESS, NULL, NULL, size); cv::Mat im = cv::imread("image.png"); cv::convert(im, im, cv::COLOR_BGR2BGRA); memcpy(&data[0], im.data, size); while (true) { cv::imshow("cpp", im); if (cv::waitKey(0) == 27) break; } }
受信側(Unity)
using System.Collections; using UnityEngine; using System.Runtime.InteropServices; using System; using Microsoft.Win32.SafeHandles; public class LR_seperated : MonoBehaviour { Texture2D texture; string MemoryName = "COLOR_IMAGE640x480"; static int w = 640; static int h = 480; static UInt32 size = (UInt32)(w * h * 4); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] static extern SafeFileHandle OpenFileMapping( uint dwDesiredAccess, bool bInheritHandle, string lpName); [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr MapViewOfFile( SafeFileHandle hFileMappingObject, UInt32 dwDesiredAccess, UInt32 dwFileOffsetHigh, UInt32 dwFileOffsetLow, UIntPtr dwNumberOfBytesToMap); const UInt32 STANDARD_RIGHTS_REQUIRED = 0x000F0000; const UInt32 SECTION_QUERY = 0x0001; const UInt32 SECTION_MAP_WRITE = 0x0002; const UInt32 SECTION_MAP_READ = 0x0004; const UInt32 SECTION_MAP_EXECUTE = 0x0008; const UInt32 SECTION_EXTEND_SIZE = 0x0010; const UInt32 SECTION_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | SECTION_EXTEND_SIZE); const UInt32 FILE_MAP_ALL_ACCESS = SECTION_ALL_ACCESS; private SafeFileHandle handle; private IntPtr buffer; // Start is called before the first frame update void Start() { texture = new Texture2D(w, h, TextureFormat.BGRA32, false); handle = OpenFileMapping(FILE_MAP_ALL_ACCESS, false, MemoryName); buffer = MapViewOfFile(sHandle, FILE_MAP_ALL_ACCESS, 0, 0, new UIntPtr(size)); } // Update is called once per frame void Update() { texture.LoadRawTextureData(buffer, (int)size); texture.Apply(); GetComponent<Renderer>().material.mainTexture= texture; } }