2017-07-03 122 views
0

我有一个WPF应用程序,它使用一个名为ScreenCapture的类从我的堆栈溢出中复制出一个正在运行的Handbrake可执行文件的屏幕截图。当我将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。我把简历:: 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通常使用BGR表示而不是RGB? – Dziugas

回答

2

由于您的图像水平拉伸,我打赌你选择了错误的像素格式。 (它没有垂直延伸,也没有对角倾斜,所以步幅是正确的。)CV_8UC3指定每像素24位,但我认为您的BMP文件使用每像素32位。

将您的像素格式切换为CV_8UC4,或更好的方式是从图像中读取bits per pixel的编号并根据此格式选择正确的CV格式。


边注:由于你在做sc.WriteBitmapToFile()其次opencv.DoSomething(Image.FromFile(),你是如何捕捉截图整个位是无关紧要的。您正在读取文件中的位图;这就是关键所在。

+0

这个伎俩!非常感谢。我的代表太低而无法回答。 –

相关问题