2

So I originally asked a question here about taking faster screen captures using win api as compared to PIL. I was able to succesfully capture the screen via BitBlt.

Now I am unsure how to convert the bitmap into a form that can be used with OpenCV. OpenCV doesn't have any support for bitmaps, and when I print(im) it is a ~14k long 1D array. OpenCV can't do anything with 1D, and I have tried to reshape it with NUMPY with no success.

def take_screenshot1(hwnd):
  wDC = win32gui.GetWindowDC(hwnd)
  dcObj=win32ui.CreateDCFromHandle(wDC)
  cDC=dcObj.CreateCompatibleDC()
  dataBitMap = win32ui.CreateBitmap()
  dataBitMap.CreateCompatibleBitmap(dcObj, 765, 503)
  cDC.SelectObject(dataBitMap)
  cDC.BitBlt((0, 0), (765, 503), dcObj, (0, 0), win32con.SRCCOPY)

  im = dataBitMap.GetBitmapBits(False)
  #img = np.array(im)
  #cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

  dcObj.DeleteDC()
  cDC.DeleteDC()
  win32gui.ReleaseDC(hwnd, wDC)
  win32gui.DeleteObject(dataBitMap.GetHandle())

edit: Here is the working code:

def take_screenshot1(hwnd):
  wDC = win32gui.GetWindowDC(hwnd)
  dcObj=win32ui.CreateDCFromHandle(wDC)
  cDC=dcObj.CreateCompatibleDC()
  dataBitMap = win32ui.CreateBitmap()
  dataBitMap.CreateCompatibleBitmap(dcObj, 765, 503)
  cDC.SelectObject(dataBitMap)
  cDC.BitBlt((0, 0), (765, 503), dcObj, (0, 0), win32con.SRCCOPY)

  im = dataBitMap.GetBitmapBits(False)

  img = np.array(im).astype(dtype="uint8")

  img.shape = (503,765,4)

  cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

  dcObj.DeleteDC()
  cDC.DeleteDC()
  win32gui.ReleaseDC(hwnd, wDC)
  win32gui.DeleteObject(dataBitMap.GetHandle())
Community
  • 1
  • 1
Kyle Hunter
  • 257
  • 3
  • 10
  • `np.fromstring(im, dtype='uint8').reshape(height,width,4)` – Dan Mašek Oct 28 '16 at 17:53
  • @DanMašek that doesn't work.. ValueError: total size of new array must be unchanged – Kyle Hunter Oct 28 '16 at 18:56
  • Oh, I think I see why. You have `dataBitMap.GetBitmapBits(False)`, whereas when I was testing it, I called it with `True` to get a string that could be loaded as above. – Dan Mašek Oct 28 '16 at 19:52
  • Do this work for you? If I do 20 screenshot they always are the same, I take 1 screenshot every second of a game, image in the window is changing. – sliders_alpha Nov 19 '16 at 07:02
  • Hi @KyleHunter I'm trying to do what I believe is the exact same thing -- But the result is an OpenCV image that is vertically stretched and has vertical banding. It looks something like this (sorry, this is down-sized): http://imgur.com/U39CAXH Any ideas on why this result is happening? – Allen Pestaluky Jan 21 '17 at 23:26
  • Nevermind! I figured out my dumb mistake: I just needed to use cv2.cvtColor(img, cv2.COLOR_RGBA2RGB), since my bitmap source was RGBA and I needed RGB from it. – Allen Pestaluky Jan 21 '17 at 23:31
  • `signedIntsArray = bmp.GetBitmapBits(True)` and `img = np.fromstring(signedIntsArray, dtype='uint8')` is a LOT faster than using `GetBitmapBits(False)` ( http://stackoverflow.com/a/41792925/1123295 ) – Allen Pestaluky Jan 22 '17 at 15:50

1 Answers1

2

GetBitmapBits() in its Python incarnation returns an array of signed ints instead of unsigned bytes. You should first convert it to unsigned bytes and then do as @DanMašek said.

hidefromkgb
  • 5,834
  • 1
  • 13
  • 44