質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

2回答

5162閲覧

C++とC#での画像データのメモリ共有について

soramama

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

3クリップ

投稿2018/10/16 09:24

編集2018/10/16 14:20

前提・実現したいこと

ここに質問の内容を詳しく書いてください。

C++でOpenCVを使い画像を共有メモリに出力し
C#のアプリケーションで共有メモリにアクセスしてPictureBoxに画像を
反映させたいのですがプログラム初心者でどのように処理すればいいのか
わからないので良ければアドバイスの方よろしくお願いいたします。

発生している問題・エラーメッセージ

該当のソースコード

コード #include "stdafx.h" #include <Windows.h> #include <opencv2/opencv.hpp> #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> #include <stdlib.h> #include <iostream> #include "BmpMem.h" #define _CRTBG_MAP_ALLOC #define BMP_SHARE_MEM _T ("BMP_SHARED_MEMORY") #define MEMORY_SIZE 3000 * 2000 * 4 using namespace std; using namespace cv; BmpMem::BmpMem() { } BmpMem::~BmpMem() { } int BmpMem::CreateMapObject(void) { try { // マッピングオブジェクト作成 m_hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMORY_SIZE, BMP_SHARE_MEM); if (m_hMapping == NULL) { cout << "マップドファイルオブジェクトの作成に失敗しました" << endl; getchar(); return -1; } // 共有メモリをマッピング m_lpBuff = (LPSTR)::MapViewOfFile(m_hMapping, FILE_MAP_WRITE, 0, 0, 0); if (m_lpBuff == NULL) { cout << "MapViewOfFileエラー" << endl; getchar(); return -1; } ::ZeroMemory(m_lpBuff, MEMORY_SIZE); } catch (...) { cout << endl << "CreateMapObject Exception !" << endl; getchar(); } return 0; } void BmpMem::OutMem(unsigned long* bmp_img) { try { memcpy(m_lpBuff, bmp_img, (16 + (m_ImageWidth * m_ImageHeight)) * 4); cout << "出力が完了しました" << endl; } catch (...) { cout << endl << "OutMem Exception !" << endl; getchar(); } } void BmpMem::OutBmpData(cv::Mat* src) { m_ImageWidth = src->rows; m_ImageHeight = src->cols; IplImage IplImg; BITMAPINFO info; BITMAPFILEHEADER bmpHeader; try { IplImg = *src; HANDLE hHandle; unsigned long* bmpData; hHandle = GetProcessHeap(); bmpData = (LPDWORD)HeapAlloc(hHandle, HEAP_ZERO_MEMORY, (16 + (m_ImageWidth * m_ImageHeight)) * 4); cout << "共有メモリに出力します" << endl; iplTobmp(&IplImg, info, bmpHeader, bmpData); OutMem(bmpData); HeapFree(hHandle, 0, bmpData); cout << "出力が完了しました" << endl; } catch (...) { cout << endl << "OutBmpData Exception !" << endl; getchar(); } } Mat BmpMem::InBmpData() { HANDLE mh_lpBuff = (LPSTR)::OpenFileMapping(FILE_MAP_ALL_ACCESS, false, BMP_SHARE_MEM); // 共有メモリをマッピング LPSTR mp_lpBuff = (LPSTR)::MapViewOfFile(mh_lpBuff, FILE_MAP_WRITE, 0, 0, 0); if (mp_lpBuff == NULL) { cout << "MapViewOfFileエラー" << endl; getchar(); } unsigned long bmpInfo[16] = {}; memcpy(bmpInfo, mp_lpBuff, 16 * 4); cout << "インフォ部を読み込みました" << endl; int width = bmpInfo[6]; int height = bmpInfo[7]; cv::Mat image; cv::Mat bmpImage(cvSize(bmpInfo[6], bmpInfo[7]), CV_8UC3, cv::Scalar(0)); cout << "Mat宣言完了" << endl; try { unsigned char b, g, r; unsigned long pixel; cout << "変数宣言完了しました" << endl; for (int countHeight = 0; countHeight < bmpInfo[7]; countHeight++) { //cout << countHeight << "行目を読み込みます" << endl; for (int countWidth = 0; countWidth < bmpInfo[6]; countWidth++) { CopyMemory(&pixel, (mp_lpBuff + ((16 + countWidth + ((bmpInfo[7] - countHeight - 1) * bmpInfo[6])) * 4)), sizeof(unsigned long)); b = pixel; g = pixel >> 8; r = pixel >> 16; bmpImage.at<cv::Vec3b>(countHeight, countWidth)[0] = b; bmpImage.at<cv::Vec3b>(countHeight, countWidth)[1] = g; bmpImage.at<cv::Vec3b>(countHeight, countWidth)[2] = r; } //cout << "読み込み完了しました" << endl; } cout << "読み込み完了しました" << endl; } catch (...) { cout << endl << "CloseMapObject Exception !" << endl; getchar(); } return bmpImage; } void BmpMem::CloseMapObject(void) { try { UnmapViewOfFile(m_lpBuff); CloseHandle(m_hMapping); } catch (...) { cout << endl << "OutBmpData Exception !" << endl; getchar(); } } void BmpMem::iplTobmp(const IplImage* srcIplImage, BITMAPINFO& bmpInfo, BITMAPFILEHEADER& bmpHeader, unsigned long* bmpData) { int width = srcIplImage->width; int height = srcIplImage->height; // ビットマップのヘッダーを0で初期化 ZeroMemory(&bmpHeader, sizeof(bmpHeader)); bmpHeader.bfType = 'BM'; // ファイルタイプ bmpHeader.bfSize = (16 + width * height) * 4; // ファイル全体のサイズ bmpHeader.bfReserved1 = 0; // 予約領域 常に0 bmpHeader.bfReserved2 = 0; // 予約領域 常に0 bmpHeader.bfOffBits = 16; // ファイル先頭から画像データまでのオフセット値 // bmpData[0-4]にヘッダ情報を格納 bmpData[0] = bmpHeader.bfType; bmpData[1] = bmpHeader.bfSize; bmpData[2] = bmpHeader.bfReserved1; bmpData[3] = bmpHeader.bfReserved2; bmpData[4] = bmpHeader.bfOffBits; // ビットマップのインフォを0で初期化 ZeroMemory(&bmpInfo, sizeof(bmpInfo)); bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // Info構造体のサイズ 40 bmpInfo.bmiHeader.biWidth = width; // 画像の幅[pix] bmpInfo.bmiHeader.biHeight = height; // 画像の高さ[pix] bmpInfo.bmiHeader.biPlanes = 1; // プレーン数 常に1 bmpInfo.bmiHeader.biBitCount = 32; // 1画素あたりのビット数 bmpInfo.bmiHeader.biCompression = BI_RGB; // 圧縮形式 bmpInfo.bmiHeader.biSizeImage = 0; // 画像データのサイズ(byte) BI_RGBは0でも可 bmpInfo.bmiHeader.biXPelsPerMeter = 0; // 水平方向1[m]あたりの画素数 0でも可 bmpInfo.bmiHeader.biYPelsPerMeter = 0; // 垂直方向1[m]あたりの画素数 0でも可 bmpInfo.bmiHeader.biClrUsed = 0; // カラーテーブルの色数 0でも可 bmpInfo.bmiHeader.biClrImportant = 0; // 表示に必要なカラーテーブルの色数 0でも可 // bmpData[5-15]にインフォ情報を格納 bmpData[5] = bmpInfo.bmiHeader.biSize; bmpData[6] = bmpInfo.bmiHeader.biWidth; bmpData[7] = bmpInfo.bmiHeader.biHeight; bmpData[8] = bmpInfo.bmiHeader.biPlanes; bmpData[9] = bmpInfo.bmiHeader.biBitCount; bmpData[10] = bmpInfo.bmiHeader.biCompression; bmpData[11] = bmpInfo.bmiHeader.biSizeImage; bmpData[12] = bmpInfo.bmiHeader.biXPelsPerMeter; bmpData[13] = bmpInfo.bmiHeader.biYPelsPerMeter; bmpData[14] = bmpInfo.bmiHeader.biClrUsed; bmpData[15] = bmpInfo.bmiHeader.biClrImportant; cout << "情報を出力しました" << endl; for (int count = 0; count < 16; count++) { cout << count << " : " << bmpData[count] << endl; } unsigned long pixel; unsigned char r, g, b; for (int countHeight = 0; countHeight < height; countHeight++) { for (int countWidth = 0; countWidth < width; countWidth++) { // Brue,Green,Redの画素値を取得する b = srcIplImage->imageData[srcIplImage->widthStep * countHeight + countWidth * 3]; g = srcIplImage->imageData[srcIplImage->widthStep * countHeight + countWidth * 3 + 1]; r = srcIplImage->imageData[srcIplImage->widthStep * countHeight + countWidth * 3 + 2]; //imageBuffer->push_back(b); //imageBuffer->push_back(g); //imageBuffer->push_back(r); // pixelを初期化する pixel = 0x00000000; // rは16bitシフト,gは8bitシフト,bはそのままでpixelに格納 pixel = (r << 16) + (g << 8) + b; // pixelをbmpDataに格納 bmpData[16 + countWidth + (height - countHeight - 1) * width] = pixel; } //cout << countHeight << "行目の画素データを格納します" << endl; } cout << "画像を出力しました" << endl; } BmpMem.h #pragma once #include <Windows.h> #include <vector> #include <opencv2/core.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> class BmpMem { public: BmpMem(); ~BmpMem(); private: HANDLE m_hMapping; LPSTR m_lpBuff; int m_memSize; int m_ImageWidth; int m_ImageHeight; // 共有メモリにデータ書き込み void OutMem(unsigned long*); // IplImageからBMP(DIB)へ変換する void iplTobmp(const IplImage* srcIplImage, BITMAPINFO& bmpInfo, BITMAPFILEHEADER& bmpHeader, unsigned long* bmpData); public: // 共有メモリの作成 int CreateMapObject(void); // ビットマップデータの書き込み void OutBmpData(cv::Mat *src); // ビットマップデータの読み込み //void InBmpData(); cv::Mat InBmpData(); // 共有メモリオブジェクトの破棄 void CloseMapObject(void); }; 読み込み部分 #include "stdafx.h" #include <conio.h> #include <opencv2/core.hpp> #include <opencv2/opencv.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/highgui.hpp> #include <iostream> #include "BmpMem.h" using namespace std; using namespace cv; int _tmain(int argc, _TCHAR* argv[]) { int key; Mat img; Mat returnImage; cout << "共有メモリのオープンに成功しました" << endl; img = imread("D:\デスクトップ\Project1\Project1\954704.png",1); if (img.empty()) { cout << "画像は読み込まれませんでした\nプログラムを終了します" << endl; return -1; } cout << "画像のオープンに成功しました" << endl; BmpMem *pBmp = new BmpMem; if (pBmp->CreateMapObject() == -1) { cout << "共有メモリ(画像)のオープンに失敗しました。" << endl; getchar(); return -1; } pBmp->OutBmpData(&img); cout << "読み込みを開始します" << endl; returnImage = pBmp->InBmpData(); cout << "読み込みが完了しました" << endl; while (true) { cv::imshow("書き込み元の画像", img); cv::imshow("共有メモリ内の画像", returnImage); waitKey(); Sleep(100); if (_kbhit() == TRUE) { break; } } pBmp->CloseMapObject(); delete pBmp; _CrtDumpMemoryLeaks(); return 0; }
C++ C#

試したこと

C++ 共有メモリを作り,画像の出力はできました

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。
VisualStudio2017
OpenCV 3.4.1

MemoryMappedFileをどのようにして扱えばいいのか
で手が止まってます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2018/10/16 09:38

ソースコードを提示してください。ソースは、<code>ボタンで、’’’の枠の中に貼り付けてください
soramama

2018/10/16 14:21

ご返事ありがとうございます ソースコードの方掲示しましたのでよろしくお願いします。
guest

回答2

0

こんにちは。

共有メモリ上のデータ形式が分かりませんが、C#を使う場合は Byte[]が多いと思います。
Byte[]からBitmapへ変換するには、ImageConverterクラスのByteArrayToImageメソッドを使えば良いようです。

しかし、プログラミング初心者にはそこそこ荷が思いと思いますし、手間がそこそこかかります。C++側でbmpファイルへ保存してC#で読み込むと簡単ですよ。
C++で画像を加工し続けるものを高速(もしくは大量)に表示したいというのでなければ性能的にも許容範囲に収まる可能性はあると思います。

投稿2018/10/16 11:16

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pepperleaf

2018/10/16 11:28

多分、C#では直接、OpenCVを使えないので、C++ から、OpenCVを使ってメインの処理をを C# で行うのでは? 確か、Memoryをロックし、共有メモリでアクセスすれば、良いのですが、具体的な方法が思い出せません。(人の作ったのをそのまま、使っているので)
pepperleaf

2018/10/16 13:48 編集

C++側で、.NETから、OpenCVで扱える形式(アンマネージ)に変換するだけです。メモリ管理が違うので、ちょっと注意が必要です。ただ、知っている人なら、簡単な筈なので、今から、調べるより、知っている人の回答が無いかと。 あ、使った方法は、Bitmap形式。C++で、OpenCV の Mat ⇔ Bitmap変換をする。
testset

2018/10/16 16:07

過去に対応した事案を記載しておきます: 1. C++上でCvMatからビットマップサイズ(メモリをC#から確保する量)を取得するAPIを公開 2. C#側でbyte配列を指定されたサイズ分を確保 3. C++側に2のメモリを渡してCvMatから画像データをコピー 4. `Bitmap(Int32, Int32, Int32, PixelFormat, IntPtr)` でビットマップ化した記憶があります。(補足: Bitmapインスタンスを使い終わるまでIntPtrは開放してはいけないのがつらかった....) ※残念ながらソースがないので、正式回答は出来かねます ※C++の再配布パッケージをインストールさせたくないために上記手順を行っていました(が、OpenCVが再配布パッケージが必須であることを知って絶望した記憶があります)
guest

0

共有メモリは使って無く、C++ もC++/CLI ですが、以下のようなコードで Bitmapにしてます。

C++

1 2cv::Mat MatData; // Matデータ 3 4Bitmap ^MatToBmp() 5{ 6 Bitmap ^bmp = gcnew Bitmap(MatData.cols, MatData.rows, Imaging::PixelFormat::Format24bppRgb); 7 Imaging::BitmapData^ bmpData = bmp->LockBits(Rectangle(0, 0, bmp->Width, bmp->Height), 8 Imaging::ImageLockMode::WriteOnly, Imaging::PixelFormat::Format24bppRgb 9 ); 10 11 int lineSize = bmpData->Stride; 12 uint8_t *destData = (uint8_t *)bmpData->Scan0.ToPointer(); 13 14 for (int y = 0; y < MatData.rows; y++) { 15 for (int x = 0; x < MatData.cols; x++) { 16 destData[y * lineSize + x * 3 + 0] = MatData.at<cv::Vec3b>(y, x)[0]; // B 17 destData[y * lineSize + x * 3 + 1] = MatData.at<cv::Vec3b>(y, x)[1]; // G 18 destData[y * lineSize + x * 3 + 2] = MatData.at<cv::Vec3b>(y, x)[2]; // R 19 } 20 } 21 bmp->UnlockBits(bmpData); 22 return bmp; 23}

こんな感じで、Bitmapに変換し、
C#は単に呼び出すだけ。

C#

1 Bitmap bmp = MatToBmp();

実際には、エラー処理とか、色々とありますが、、。

投稿2018/10/17 14:22

pepperleaf

総合スコア6383

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問