「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;
}
}