我使用 Win32gui 从窗口截图创建了一个图像。该对象具有类型:
object 'PyCBitmap' - assoc is 000002AF9A64DB50, vi=<None>
然后我想将其传递给 OpenCV 进行分析。我使用以下方法成功读取了保存的 .bmp 文件:
cv2.imread(img_file, 0)
尝试对 PyCBitmap 对象使用
cv2.imread
时出现以下错误:
TypeError: bad argument type for built-in operation
我的问题是:
如何将 PyCBitmap 对象转换为
cv2.imread
可接受的类型,而不必先将对象另存为 .bmp 文件?
提前致谢,
贝扎德
p.s 我正在使用带有 python 绑定的 opencv 3.1,我很乐意遵循用 C++ 或 python 编写的建议 :)
一直在找同样的东西,结合其他几个SO答案终于找到了:
基本上,我想出的代码是:
import PIL, numpy, cv2
bmpinfo = dataBitMap.GetInfo()
bmparray = numpy.asarray(dataBitMap.GetBitmapBits(), dtype=numpy.uint8)
pil_im = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmparray, 'raw', 'BGRX', 0, 1)
pil_array = numpy.array(pil_im)
cv_im = cv2.cvtColor(pil_array, cv2.COLOR_RGB2BGR)
简要说明:Python OpenCV 只使用 numpy 数组,所以技巧实际上是将字节转换为正确的 numpy 数组格式。事实证明,为此您需要一个像 PIL 这样的图像处理库,它可以处理特定于图像的逻辑,例如剪切 alpha 通道。输入数据一般是RGBX格式,PIL转成RGB,OpenCV转成自己喜欢的BGR。
我对此进行了分析,不幸的是,它比
GetBitmapBits()
慢得多,并且将其元组结果转换为数组。
我知道我来晚了,但也许它会在未来帮助某人,因为这需要很长时间才能找到。这是速度的巨大提升。出于某种原因,numpy.asarray() 和许多其他 numpy 数组创建方法非常慢。我所有的发现主要基于 Adam S 的回答。
线
bmparray = numpy.array(bitmap.GetBitmapBits()).astype(numpy.uint8)
在我的机器上大约需要 0.25 秒,这不是很好。要解决此问题,我们可以避免在此处创建数组。
bmpinfo = bitmap.GetInfo()
bmpbits = bitmap.GetBitmapBits(True)
pil_im = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpbits, 'raw', 'BGRX', 0, 1)
pil_array = numpy.array(pil_im)
img = cv2.cvtColor(pil_array, cv2.COLOR_RGB2BGR)
这是我的代码优化版本,它可以在 1 秒内截取约 55 个屏幕截图,与每秒获取约 6 个屏幕截图的旧方法相对:
import win32gui
import win32ui
import win32con
import numpy, cv2
from PIL import Image
def convert(bitmap) -> cv2.Mat:
bmpinfo = bitmap.GetInfo()
bmpbits = bitmap.GetBitmapBits(True)
pil_im = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpbits, 'raw', 'BGRX', 0, 1)
pil_array = numpy.array(pil_im)
return cv2.cvtColor(pil_array, cv2.COLOR_RGB2BGR)
def take_screen_shot():
# https://stackoverflow.com/questions/3586046/fastest-way-to-take-a-screenshot-with-python-on-windows
w = 1920 # set this
h = 1080 # set this
hwnd = win32gui.FindWindow(None, "co-op games.txt - Notepad")
wDC = win32gui.GetWindowDC(hwnd)
dcObj=win32ui.CreateDCFromHandle(wDC)
cDC=dcObj.CreateCompatibleDC()
dataBitMap = win32ui.CreateBitmap()
dataBitMap.CreateCompatibleBitmap(dcObj, w, h)
cDC.SelectObject(dataBitMap)
cDC.BitBlt((0,0),(w, h) , dcObj, (0,0), win32con.SRCCOPY)
image = convert(dataBitMap)
# Free Resources
dcObj.DeleteDC()
cDC.DeleteDC()
win32gui.ReleaseDC(hwnd, wDC)
win32gui.DeleteObject(dataBitMap.GetHandle())
return image