13

私のC++dllでは、バイト配列からMatを作成しています。

BYTE * ptrImageData;  //Image data is in this array passed to this function

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData);

画像は、元の画像ではなく、灰色の色合いで作成されています。

これはバイト配列からMatを作成する適切な方法ですか?

コードをご覧ください

ptrImageDataは、C#コードからC++dllに渡されます。

画像データを渡すためのC#コード

System.Drawing.Image srcImage //Has the image
MemoryStream ms = new MemoryStream(); 
Marshal.FreeHGlobal(ptrImageData); 
srcImage.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); 
byte[] imgArray = ms.ToArray();
ms.Dispose();


int size1 = Marshal.SizeOf(imgArray[0]) * imgArray.Length;
IntPtr ptrImageData = Marshal.AllocHGlobal(size1);
Marshal.Copy(imgArray, 0, ptrImageData, imgArray.Length);

//Calling C++ dll function
ProcessImage(ptrImageData, srcImage.Width, srcImage.Height);

Marshal.FreeHGlobal(ptrImageData);
4

3 に答える 3

3

C++ コードは、バッファが従来の RGB8 形式であると仮定して、提供された画像データのマトリックスラッパーを作成するという点で問題ないように見えます。このコンストラクターはバッファーをコピーしないMatため、このインスタンスの期間中はバッファーを有効にしておく(またはコピーする) 必要があることに注意してください。

Mat newImg = Mat(nImageHeight, nImageWidth, CV_8UC3, ptrImageData);

問題はあなたのC#コードにあるようです。私は C# 開発者ではありませんが、できる限りお手伝いします。メモリ ストリームを作成し、JPEG コーデックを使用して、イメージの圧縮バージョンをファイルであるかのようにバッファーに書き込みます。しかし、それは想定されているデータ形式ではないcv::Matため、基本的にゴミが表示されます (圧縮されたデータが非圧縮として解釈されます)。

インスタンスSystem.Image.Drawing.Imageを指定すると、ラッパーBitmapオブジェクトを直接作成できます (またはas、単純なダウンキャストであるため、 を使用することもできます)。次に、Bitmap.LockBits()メソッドを使用して、基になる画像データへのポインターを取得できます。

Bitmap bmp = new Bitmap(sourceImage);

// Lock the bitmap's bits.  
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
System.Drawing.Imaging.BitmapData bmpData =
    bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
    bmp.PixelFormat);

// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;

// Declare an array to hold the bytes of the bitmap.
int bytes  = Math.Abs(bmpData.Stride) * bmp.Height;
byte[] rgbBuffer = new byte[bytes];

// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbBuffer, 0, bytes);

// Do your OpenCV processing...
// ...

// Unlock the bits.
bmp.UnlockBits(bmpData);

そして、rgbBufferOpenCVに渡すことができます。

元のコードのメモリ管理が完全に正しいとは確信していませんが、バッファの所有権の範囲がロックおよびロック解除メソッドの呼び出し内にある場合は、上記が機能します。画像データがこのコード ブロックより長く存続する場合は、バッファをコピーする必要があります。

ピクセル形式にも注意してくださいImage/Bitmap。インスタンスに実際に RGB8 データが含まれていることを確認する必要があります。OpenCVcv::Matにはさまざまなフラグがあるため、さまざまなインメモリ イメージ フォーマットを操作できます。ただし、これらは、PNG、TIFF などのディスク上の (通常は圧縮された) 形式と同じではないことに注意してください。

于 2016-09-28T11:39:31.213 に答える
0

ドキュメントへのリンクは次のとおりです。http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-mat

一般に、次の 2 つの点に注意する必要があります。

  1. 外部データをマトリックス コンストラクターに渡す場合、外部データは自動的に割り当て解除されないため、注意する必要があります。OpenCV マトリックスにメモリを考慮させたい場合は、マトリックスをコピーする必要があります ( Mat::cloneまたはMat::copyToメソッドを使用するなど、多くの方法で実行できます。
  2. 外部データは連続していない可能性があります。つまり、行のサイズが、幅×チャネル数×データ要素のサイズより大きい場合があります。したがって、コンストラクターの最後の引数として「step」を指定することができます。外部データを手動で割り当て、それが連続的であることを 100% 確信している場合、ステップを通過せず、自動ステップ計算に依存する可能性があります。

私は C# に詳しくありませんが、ProcessImage 呼び出しの直後にデータを解放しているように思えます。したがって、ProcessImage が非同期であるか、何らかの方法でマトリックスをキャッシュする (つまり、マトリックスの寿命が ProcessImage 呼び出しよりも長い) 場合は、メモリ管理に注意する必要があります。

于 2015-07-24T09:15:39.460 に答える
0

はい、これはバイト配列から Mat を作成する 1 つの方法です。配列には、それが何をしていると思うかが含まれていることに注意する必要があります。

画像は、元の画像ではなく、グレーの色合いで作成されています。

newImgで画像を取得していますか?元のデータのピクセル形式は何ですか?

赤と青のチャンネルを切り替えたのかもしれません。次の行は、チャネルを交換します。

cv::cvtColor(newImg,swappedImg,CV_RGB2BGR);
于 2013-03-22T18:23:22.767 に答える