2017-07-03 23 views
0

Stack OverflowからコピーしたScreenCaptureというクラスを使用して、実行中のHandbrake実行可能ファイルのスクリーンショットを取得するWPFアプリケーションがあります。System.Drawing.Bitmapオブジェクトからcv :: Matに変換すると、ビットマップがマングリングされる

public class ScreenCapture 
{ 
    [DllImport("user32.dll")] 
    static extern int GetWindowRgn(IntPtr hWnd, IntPtr hRgn); 

    //Region Flags - The return value specifies the type of the region that the function obtains. It can be one of the following values. 
    const int ERROR = 0; 
    const int NULLREGION = 1; 
    const int SIMPLEREGION = 2; 
    const int COMPLEXREGION = 3; 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect); 

    [DllImport("gdi32.dll")] 
    static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); 

    [DllImport("user32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); 

    [StructLayout(LayoutKind.Sequential)] 
    public struct RECT 
    { 
     public int Left, Top, Right, Bottom; 

     public RECT(int left, int top, int right, int bottom) 
     { 
      Left = left; 
      Top = top; 
      Right = right; 
      Bottom = bottom; 
     } 

     public RECT(System.Drawing.Rectangle r) : this(r.Left, r.Top, r.Right, r.Bottom) { } 

     public int X 
     { 
      get { return Left; } 
      set { Right -= (Left - value); Left = value; } 
     } 

     public int Y 
     { 
      get { return Top; } 
      set { Bottom -= (Top - value); Top = value; } 
     } 

     public int Height 
     { 
      get { return Bottom - Top; } 
      set { Bottom = value + Top; } 
     } 

     public int Width 
     { 
      get { return Right - Left; } 
      set { Right = value + Left; } 
     } 

     public System.Drawing.Point Location 
     { 
      get { return new System.Drawing.Point(Left, Top); } 
      set { X = value.X; Y = value.Y; } 
     } 

     public System.Drawing.Size Size 
     { 
      get { return new System.Drawing.Size(Width, Height); } 
      set { Width = value.Width; Height = value.Height; } 
     } 

     public static implicit operator System.Drawing.Rectangle(RECT r) 
     { 
      return new System.Drawing.Rectangle(r.Left, r.Top, r.Width, r.Height); 
     } 

     public static implicit operator RECT(System.Drawing.Rectangle r) 
     { 
      return new RECT(r); 
     } 

     public static bool operator ==(RECT r1, RECT r2) 
     { 
      return r1.Equals(r2); 
     } 

     public static bool operator !=(RECT r1, RECT r2) 
     { 
      return !r1.Equals(r2); 
     } 

     public bool Equals(RECT r) 
     { 
      return r.Left == Left && r.Top == Top && r.Right == Right && r.Bottom == Bottom; 
     } 

     public override bool Equals(object obj) 
     { 
      if (obj is RECT) 
       return Equals((RECT)obj); 
      else if (obj is System.Drawing.Rectangle) 
       return Equals(new RECT((System.Drawing.Rectangle)obj)); 
      return false; 
     } 

     public override int GetHashCode() 
     { 
      return ((System.Drawing.Rectangle)this).GetHashCode(); 
     } 

     public override string ToString() 
     { 
      return string.Format(System.Globalization.CultureInfo.CurrentCulture, "{{Left={0},Top={1},Right={2},Bottom={3}}}", Left, Top, Right, Bottom); 
     } 
    } 
    public Bitmap GetScreenshot(IntPtr ihandle) 
    { 
     IntPtr hwnd = ihandle;//handle here 

     RECT rc; 
     GetWindowRect(new HandleRef(null, hwnd), out rc); 

     Bitmap bmp = new Bitmap(rc.Right - rc.Left, rc.Bottom - rc.Top, PixelFormat.Format32bppArgb); 
     Graphics gfxBmp = Graphics.FromImage(bmp); 
     IntPtr hdcBitmap; 
     try 
     { 
      hdcBitmap = gfxBmp.GetHdc(); 
     } 
     catch 
     { 
      return null; 
     } 
     bool succeeded = PrintWindow(hwnd, hdcBitmap, 0); 
     gfxBmp.ReleaseHdc(hdcBitmap); 
     if (!succeeded) 
     { 
      gfxBmp.FillRectangle(new SolidBrush(Color.Gray), new Rectangle(Point.Empty, bmp.Size)); 
     } 
     IntPtr hRgn = CreateRectRgn(0, 0, 0, 0); 
     GetWindowRgn(hwnd, hRgn); 
     Region region = Region.FromHrgn(hRgn);//err here once 
     if (!region.IsEmpty(gfxBmp)) 
     { 
      gfxBmp.ExcludeClip(region); 
      gfxBmp.Clear(Color.Transparent); 
     } 
     gfxBmp.Dispose(); 
     return bmp; 
    } 

    public void WriteBitmapToFile(string filename, Bitmap bitmap) 
    { 
     bitmap.Save(filename, ImageFormat.Bmp); 
    } 

以下のボタンクリックハンドラが呼び出されると、手ブレークウィンドウのスクリーンショットが取得されます。 ハードドライブに書き込んで確認してください: handbrake screen shot。 私はCLRクラスライブラリClassLibrary1 :: Class1のインスタンスを作成し、それをSystem.Drawing.Bitmapオブジェクトに渡すメソッド "DoSomething"を呼び出します。

private void button4_Click(object sender, RoutedEventArgs e) 
    { 
    string wName = "HandBrake"; 
    IntPtr hWnd = IntPtr.Zero; 
    foreach (Process pList in Process.GetProcesses()) 
    { 
     if (pList.MainWindowTitle.Contains(wName)) 
     { 
      hWnd = pList.MainWindowHandle; 

      var sc = new ScreenCapture(); 

      SetForegroundWindow(hWnd); 
      var bitmap = sc.GetScreenshot(hWnd); 

      sc.WriteBitmapToFile("handbrake.bmp", bitmap); 

      Bitmap image1 = (Bitmap)System.Drawing.Image.FromFile("handbrake.bmp", true); 

      ClassLibrary1.Class1 opencv = new ClassLibrary1.Class1(); 

      opencv.DoSomething(image1); 
     } 
    } 
    } 

Inside DoSomething私は、System.Drawing.BitmapをOpenCVクラスcv :: Matに変換しようとしています。私は残念ながら間違って代、ビットマップはまだ大丈夫であることを確認するためのcv ::関数imwriteを呼び出す:mangled handbrake screenshot

void Class1::DoSomething(Bitmap ^mybitmap) 
{ 
cv::Mat *imgOriginal; 
// Lock the bitmap's bits. 
Rectangle rect = Rectangle(0, 0, mybitmap->Width, mybitmap->Height); 
Imaging::BitmapData^ bmpData = mybitmap->LockBits(rect, Imaging::ImageLockMode::ReadWrite, mybitmap->PixelFormat); 
try 
{ 
    // Get the address of the first line. 
    IntPtr ptr = bmpData->Scan0; 

    // Declare an array to hold the bytes of the bitmap. 
    // This code is specific to a bitmap with 24 bits per pixels. 
    int bytes = Math::Abs(bmpData->Stride) * mybitmap->Height; 
    array<Byte>^rgbValues = gcnew array<Byte>(bytes); 

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

    imgOriginal = new cv::Mat(mybitmap->Height, mybitmap->Width, CV_8UC3, (void *)ptr, std::abs(bmpData->Stride)); 
    } 
    finally { mybitmap->UnlockBits(bmpData); }//Remember to unlock!!! 

    cv::imwrite("from_mat.bmp", *imgOriginal); 
} 

は、誰もが私のエラーを見つけることができますか?

+0

OpenCVは通常、RGBとは対照的にBGR表現を使用しているのでしょうか? – Dziugas

答えて

2

画像が水平に引き伸ばされているので、間違ったピクセル形式を選択していることを賭けています。 (垂直方向に伸びず、斜めに歪まないので、ストライドは正しいです)CV_8UC3は24ビット/ピクセルを指定していますが、私はあなたのBMPファイルが1ピクセルあたり32ビットを使用していると思います。

ピクセル形式をCV_8UC4に変更するか、画像からbits per pixelの番号を読み取り、それに基づいて正しいCV形式を選択します。


サイドノート:あなたはopencv.DoSomething(Image.FromFile()続いsc.WriteBitmapToFile()をやっているので、あなたはスクリーンショットをキャプチャしている方法についての全体のビットは無関係です。あなたはファイルからビットマップを読み込んでいます。それは重要なことのすべてです。

+0

それはトリックでした!どうもありがとう。私の代理人は答えとしてマークするには低すぎます。 –

関連する問題