2016-04-29 12 views
3

テスト目的で.DLLを受け取りました。この.dllには、後でハードウェアからライブ画像を処理するために使用される機能が含まれています。.DLLからビットマップを取得し、バイト[]に変換して画像に変換する

この単純な.dllでは、イメージを開いてメモリにロードし、幅と高さを取得し、イメージに変換する必要があるピクセルを取得できます。読み込み、幅の取得、高さの取得は問題ありませんが、ピクセルを取得してビットマップまたはイメージに変換することは問題です。私が受け取った

C++サンプルソース:

ApiFunc->OpenImageFile(this->OpenPictureDialog1->FileName.c_str()); 
    ApiFunc->AllocMemory(); 

    w = ApiFunc->GetImageWidth(); 
    h = ApiFunc->GetImageHeight(); 
    Image1->Width = w; 
    Image1->Height = h; 

    unsigned char* ptr = ApiFunc->GetImagePixels(); 
    COLORREF pixel; 
    int r,g,b; 
    for(int y=0; y<w; y++) 
    { 
     for(int x=0; x<h; x++) 
     { 
      r = (int)*(ptr+3*x); 
      g = (int)*(ptr+3*x+1); 
      b = (int)*(ptr+3*x+2); 

      Image1->Canvas->Pixels[y][x] = RGB(r,g,b); 
     } 
     ptr += 3*h; 
    } 

ApiFuncで、これを見つけることができます。だから今、私が試してみました何

void __fastcall TAPIFunc::LoadDll(HINSTANCE m_hMain) 
{ 
    //some others above 
    GET_IMAGE_PIXELS = (func_GET_IMAGE_PIXELS )GetProcAddress(m_hMain, "GET_IMAGE_PIXELS"); 
    //some others below 
} 
unsigned char* __fastcall TAPIFunc::GetImagePixels(void) 
{ 
    return GET_IMAGE_PIXELS(); 
} 

これまでのところ、私はバイト[を使用して試してみました]を返しますが、MarshalDirectiveExceptionがスローされます。

[DllImport("ImageTest.dll")] 
    public static extern IntPtr GET_IMAGE_PIXELS(); 

    private void OpenImage(string filename) 
    { 
     OPEN_IMAGE_FILE(filename); 
     ALLOC_MEMORY(); 
     int width = GET_IMAGE_WIDTH(); //=800 
     int height = GET_IMAGE_HEIGHT(); //=600 
     IntPtr buffer = GET_IMAGE_PIXELS(); 
     int size = width * height * 3;//not sure what the size must be, I think this is one of the issues, just following logic of one answer below. 

     //but source: https://stackoverflow.com/a/16300450/2901207 
     byte[] bitmapImageArray = new byte[size]; 
     Marshal.Copy(buffer, bitmapImageArray, 0, size); 

     Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb); 
     BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); 
     IntPtr pNative = bmData.Scan0; 
     Marshal.Copy(imageData, 0, pNative,size); 
     bitmap.UnlockBits(bmData); 
     bitmap.Save(Environment.CurrentDirectory + @"\result.bmp"); 
      using (var ms = new MemoryStream(bitmapImageArray)) 
      { 
       //both throw exception: Parameter is not valid 
       Bitmap bmp = new Bitmap(ms); 
       Image bitmapImage = Image.FromStream(ms); 
      } 
    } 

答え源:

answer 1, using bitmap.LockBits method answers 2 and 3, using memoryStream

ただ、私がテストするために有効なイメージを持っていることを確認するために、私はこのオプションを使用して、Photoshopで画像を保存: photoshoppie

醜いテスト画像:

rotated example image

結果: awesome result

美しい、それはないですか? :)

forループを使用して試してみると、クラッシュするまで実行されます。 count = 1441777まで、別の画像数= 1527793(同じ次元)まで実行されました。

 int count = 0; 
     for (int i = 0; i < width * height * 4; i++) 
     { 
      count++; 
      bitmapImageArray[i] = Marshal.ReadByte(buffer, i); 
     } 

答えて

2

実際に水平/垂直が切り替わる間違った結果が表示されます。あなたのイメージは、行ごとの行ではなく、列ごとに整理されたピクセルで取得されます(通常行われます)。

これは、外側の変数がyで、内部の変数がxで混乱しますが、外側のループがw(幅)になり、内側のループがh(高さ)になります。 。

また、RとBのコンポーネントが切り替えられているように見えます(私はここで説明はしませんが、私を信じています)。

したがって、

バイト[] bitmapImageArray =新しいバイト[サイズ]を使用してアレイを取得した後。 Marshal.Copy(buffer、bitmapImageArray、0、size);

再編成する必要があります。同じサイズの別のバッファーbitmapImageArray2を割り当て、すべてのピクセル(行ごとに、または列ごとに列ごとにループ)を割り当てます。例のように変数の名前が正しく指定されていれば、xはwに、yはhになります。

bitmapImageArray2[(y * w + x) * 3] = bitmapImageArray[(x * h + y) * 3 + 2]; 
bitmapImageArray2[(y * w + x) * 3 + 1] = bitmapImageArray[(x * h + y) * 3 + 1]; 
bitmapImageArray2[(y * w + x) * 3 + 2] = bitmapImageArray[(x * h + y) * 3]; 

注:それはそのようなコピー先の配列への書き込みsizeのためのあなたの値が正しいように思えます。

+0

ありがとうございました!私は彼らがしたのと同じループを行う答えを投稿しようとしていましたが、そのようなビットマップを構築するのは少し集中しているようです。 341msから11msに、これを最初に実行してから、残りのソリューションに従ってください – CularBytes

0

これは問題を解決しますが、私はまだ満足していませんが、もちろん結果を得るのはうれしいですが、私の意見では長くかかります。ビットマップのインスタンス化から保存前まで:241ms。これは小さく見えるかもしれませんが、流暢なビデオを制作する必要があるこのような画像を検索することは少し間違っています。

 for (int y = 0; y < width; y++) 
     { 
      for (int x = 0; x < height; x++) 
      { 
       int red = imageData[offset + 3 * x] ; 
       int green = imageData[offset + 3 * x + 1]; 
       int blue = imageData[offset + 3 * x + 2]; 
       Color color = Color.FromArgb(red, green, blue); 
       bitmap.SetPixel(y, x, color); 
      } 
      offset += 3 * height; 
     } 

@ Dimの答えが助けられました。その変換を最初に行い、その後前のように処理することで、スピードが飛躍的に向上しました。

ので結果:

private void OpenImage(string filename) 
    { 
     OPEN_IMAGE_FILE(filename); 
     ALLOC_MEMORY(); 
     int width = GET_IMAGE_WIDTH(); 
     int height = GET_IMAGE_HEIGHT(); 
     IntPtr buffer = GET_IMAGE_PIXELS(); 
     int size = width * height * 3; 
     byte[] bitmapImageArray = new byte[size]; 
     Marshal.Copy(buffer, bitmapImageArray, 0, size); 
     Bitmap bitmap3 = ConvertImage3(bitmapImageArray, height, width); 
    } 

    public Bitmap ConvertImage3(byte[] imageData, int height, int width) 
    { 
     int size = width * height * 3; 
     byte[] bitmapImageArray2 = new byte[size]; 
     for (int y = 0; y < height; y++) 
     { 
      for (int x = 0; x < width; x++) 
      { 
       bitmapImageArray2[(y * width + x) * 3] = imageData[(x * height + y) * 3 + 2]; 
       bitmapImageArray2[(y * width + x) * 3 + 1] = imageData[(x * height + y) * 3 + 1]; 
       bitmapImageArray2[(y * width + x) * 3 + 2] = imageData[(x * height + y) * 3]; 
      } 
     } 

     Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb); 
     BitmapData bmData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, bitmap.PixelFormat); 
     IntPtr pNative = bmData.Scan0; 
     Marshal.Copy(bitmapImageArray2, 0, pNative, width * height * 3); 
     bitmap.UnlockBits(bmData); 
     return bitmap; 
    } 

は今、私は何とか.DLLから画像を取得する速度を向上させる必要があり、それがこの質問の範囲外はもちろんです。

関連する問題