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

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

ただいまの
回答率

87.92%

c# - Pythonでメモリでのファイル受け渡し

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 5,838

score 13

c# - Python間でのファイルの受け渡し

現在C#とPythonでファイルの受け渡しのソフトを作成しています。
(PythonはC#からプロセスを起動して、c#-Pythonは標準出力で通信)

c#で読み込んだBitmapファイルをPython側に直接渡したいと考えています。
c#でBitmapをローカルへ保存し、そのパスをPython側へ渡して、Python側で読み込むことは容易ですが
c#でPython側のメモリアドレスを確保して、その確保したメモリへコピー。
その後にメモリの先頭アドレス、Bitmap Width Height StrideをPython側に渡して
Python側で画像を復元ということを実施したいのですが、方法がわかりません。

最終的にはPython側でnumpy Arrayに出来ればと考えていますが

試したこと
1、C# - 別のC#プロセスへVirtualAllocExでメモリを確保してコピーし、その後Bitmapを展開することは出来ます
2、c# - PythonへVirtualAllocExでメモリを確保し、C#で作成したDLLをPythonで読み込むことは出来ますが、
Python側でBitmap、Byte配列で戻せません(PythonにBitmap、Byte配列が無い?)

Python側でメモリアドレスより画像を復元するようなことはそもそも可能なのかどうかが知りたいです。

コードを一部抜粋して記載します
Visual Studio 2017 c#
Python 3.6.6

よろしくお願いします

IntPtr processHandle = OpenProcess(PROCESS_ALL_ACCESS, true, p.Id);  //pはpythonのプロセス
IntPtr processMemory = IntPtr.Zero;

// Bitmapを読み込んで、サイズ、先頭アドレスを取得する
Bitmap bmp = new Bitmap(Application.StartupPath + @"\Test.bmp");
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int intSize = bmpData.Stride * bmp.Height;

try {
    // Slaveプロセスの仮想アドレス空間のメモリを確保
    processMemory = VirtualAllocEx(processHandle, IntPtr.Zero, intSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);

    if (processMemory.Equals(IntPtr.Zero)) {
        return;
    }

    // 確保したメモリにデータをコピー
    int intWrittenSize;
    WriteProcessMemory(processHandle, processMemory, bmpData.Scan0, intSize, out intWrittenSize);

    // Python側へ情報を送信
    sw.WriteLine(bmp.Width + "," + bmp.Height + "," + bmpData.Stride + "," + processMemory);
}
finally {
    if (processMemory != IntPtr.Zero) VirtualFreeEx(processHandle, processMemory, intSize, MEM_RELEASE);
}
import numpy as np
import clr              # .netで作成したDLLを呼び出す

receive = input()
data = receive.split(',')       # カンマ区切りで分割

# data[0] Width
# data[1] Height
# data[2] Stride
# data[3] アドレス

# ---------------------------------
# .netで作成したDLLを読み出す
# ---------------------------------
clr.AddReference('ImageRead')
from ImageRead import clsImageRead      # 名前空間からクラスをインポート
imageRead = clsImageRead()      # インスタンス作成(コンストラクタが呼び出される)

# c#で作成したDLLの戻り値でBitmapを返している
img_bmp = imageRead.BitmapCreate(int(data[0]), int(data[1]), int(data[2]), str(data[3]))

# DLL内ではBitmapはできあがっているが、img_bmpにはSystem.Drwing.Bitmapの文字がはいる・・・。
# 戻り値をByte配列にした場合はSystem.Array[byte]という文字が入る
# Python側に画像や配列を戻すにはどうしたら良いのか?

# data[0] Width
# data[1] Height
# data[2] Stride
# data[3] アドレス
# 上記からnumpy arrayにできないか?
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

0

そんなあなたにはメモリマップトファイル(memory-mapped file)がお勧めです。
WindowsもUnix系も似た実装を持っていて、そのラッパを .net も Python も持ってます。
速度は恐ろしく速いので、ギガバイトクラスのファイルでも余裕です。

.NET のガイド メモリ マップト ファイル

mmap --- メモリマップファイル — Python 3.7.3 ドキュメント

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

プロセスごとにメモリは独立しています。直接的に、お望みのようなことはできません。
プロセス間通信(IPC)に付いて調べてみてください。
失礼、IPCですね。
私はMarshal.Copy で一旦Byte配列に入れてます。TCP通信なので、コードは直接参考にならないと思います。
RGBの順が異なっていたような?
それと、幅は8の倍数でないと、ズレるように思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/04 10:36

    プロセス毎にメモリは独立していることは把握しており、VirtualAllocExにて別プロセスのメモリ空間を確保し、そのアドレスにデータをコピ-しています。
    取得したメモリ空間は取得された側のメモリになりますので、アクセスすることが出来ます
    現にC# - 別のc#プロセスや、c#-Pythonプロセスへのメモリアクセスは出来ております。

    プロセス間通信を実施した場合、巨大はファイルを送信した場合に時間がかかる為、メモリに直接アクセスしたいと思いました。

    キャンセル

  • 2019/04/04 10:50

    ソケット通信で送るのが一番汎用性が高いと思いますし、手っ取り早いのも事実だと思います。
    byte列をPython側でソケットで送りつけ、Python側でNumpyで復元はまだ試していませんが、おそらく可能だと思います(RGBの順はお察しの通り違いますね)
    (そもそも標準入出力で送りつけたらどうなるのか?)

    ソケット通信での転送速度
    メモリでの転送速度
    ディスクに保存してパスを渡して再度読み込む速度
    一番高速なのはメモリだと考えており、上記手法が存在するのかが知りたいと思い投稿しました
    ちなみに画像サイズは100Mbyteとかなり巨大です

    キャンセル

0

共有メモリ
OS によって方法は異なります。

しかし、IPC で遅くて使い物にならないのであればそれほど改善はできないかもしれません。
一番速いのは複数のプロセスを使わないことなので、プロセスを統一してください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 87.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る