How to optimize conversion from PyCBitmap to OpenCV image
Question:
I’ve got this bit of code, and it works… But it runs very slow:
hwin = win32gui.GetDesktopWindow()
width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
hwindc = win32gui.GetWindowDC(hwin)
srcdc = win32ui.CreateDCFromHandle(hwindc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, width, height)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (width, height), srcdc, (left, top), win32con.SRCCOPY)
signedIntsArray = bmp.GetBitmapBits(False)
img = np.array(signedIntsArray).astype(dtype="uint8") # This is REALLY slow!
img.shape = (height,width,4)
srcdc.DeleteDC()
memdc.DeleteDC()
win32gui.ReleaseDC(hwin, hwindc)
win32gui.DeleteObject(bmp.GetHandle())
return cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
This code grabs the entire windows desktop (both displays) and converts it to an OpenCV image that I use later. I believe this conversion is running slower than it could, if it was reworked a little. Specifically, the np.array(signedIntsArray) call is really slow!
Any thoughts on how to be a bit faster at converting a desktop capture into an OpenCV image?
Answers:
First time working with Python. I think I have a better understanding of now of the data structures. Here’s the fix that drastically improves performance:
Change:
signedIntsArray = bmp.GetBitmapBits(False)
img = np.array(signedIntsArray).astype(dtype="uint8")
to:
signedIntsArray = bmp.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
and speed is greatly increased!
This is because it’s a lot faster for the np library to create an array from a string than from a tuple.
The use of np.fromstring is now deprecated so you can use this:
signedIntsArray = bmp.GetBitmapBits(True)
img = np.frombuffer(signedIntsArray, dtype=np.uint8)
I’ve got this bit of code, and it works… But it runs very slow:
hwin = win32gui.GetDesktopWindow()
width = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN)
height = win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
left = win32api.GetSystemMetrics(win32con.SM_XVIRTUALSCREEN)
top = win32api.GetSystemMetrics(win32con.SM_YVIRTUALSCREEN)
hwindc = win32gui.GetWindowDC(hwin)
srcdc = win32ui.CreateDCFromHandle(hwindc)
memdc = srcdc.CreateCompatibleDC()
bmp = win32ui.CreateBitmap()
bmp.CreateCompatibleBitmap(srcdc, width, height)
memdc.SelectObject(bmp)
memdc.BitBlt((0, 0), (width, height), srcdc, (left, top), win32con.SRCCOPY)
signedIntsArray = bmp.GetBitmapBits(False)
img = np.array(signedIntsArray).astype(dtype="uint8") # This is REALLY slow!
img.shape = (height,width,4)
srcdc.DeleteDC()
memdc.DeleteDC()
win32gui.ReleaseDC(hwin, hwindc)
win32gui.DeleteObject(bmp.GetHandle())
return cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
This code grabs the entire windows desktop (both displays) and converts it to an OpenCV image that I use later. I believe this conversion is running slower than it could, if it was reworked a little. Specifically, the np.array(signedIntsArray) call is really slow!
Any thoughts on how to be a bit faster at converting a desktop capture into an OpenCV image?
First time working with Python. I think I have a better understanding of now of the data structures. Here’s the fix that drastically improves performance:
Change:
signedIntsArray = bmp.GetBitmapBits(False)
img = np.array(signedIntsArray).astype(dtype="uint8")
to:
signedIntsArray = bmp.GetBitmapBits(True)
img = np.fromstring(signedIntsArray, dtype='uint8')
and speed is greatly increased!
This is because it’s a lot faster for the np library to create an array from a string than from a tuple.
The use of np.fromstring is now deprecated so you can use this:
signedIntsArray = bmp.GetBitmapBits(True)
img = np.frombuffer(signedIntsArray, dtype=np.uint8)