代码之家  ›  专栏  ›  技术社区  ›  Claudiu

带有16位图像数据的Image.frombuffer

  •  0
  • Claudiu  · 技术社区  · 13 年前

    如果我的窗口处于32位颜色深度模式,则以下代码将从窗口获取一个漂亮的PIL图像:

    def image_grab_native(window):
        hwnd = win32gui.GetDesktopWindow()
    
        left, top, right, bot = get_rect(window)
        w = right - left
        h = bot - top
    
        hwndDC = win32gui.GetWindowDC(hwnd)
        mfcDC  = win32ui.CreateDCFromHandle(hwndDC)
        saveDC = mfcDC.CreateCompatibleDC()
    
        saveBitMap = win32ui.CreateBitmap()
        saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)
    
        saveDC.SelectObject(saveBitMap)
        saveDC.BitBlt((0, 0), (w, h),  mfcDC,  (left, top),  win32con.SRCCOPY)
    
        bmpinfo = saveBitMap.GetInfo()
        bmpstr = saveBitMap.GetBitmapBits(True)
    
        im = Image.frombuffer(
            'RGB',
            (bmpinfo['bmWidth'], bmpinfo['bmHeight']),
            bmpstr, 'raw', 'BGRX', 0, 1)
    
        win32gui.DeleteObject(saveBitMap.GetHandle())
        saveDC.DeleteDC()
        mfcDC.DeleteDC()
        win32gui.ReleaseDC(hwnd, hwndDC)
    
        return im
    

    但是,在16位模式下运行时,我得到错误:

    >>> image_grab_native(win)
    Traceback (most recent call last):
      File "<pyshell#3>", line 1, in <module>
        image_grab_native(win)
      File "C:\claudiu\bumhunter\finderbot\ezpoker\utils\win32.py", line 204, in image_grab_native
        bmpstr, 'raw', 'BGRX', 0, 1)
      File "c:\python25\lib\site-packages\PIL\Image.py", line 1808, in frombuffer
        return apply(fromstring, (mode, size, data, decoder_name, args))
      File "c:\python25\lib\site-packages\PIL\Image.py", line 1747, in fromstring
        im.fromstring(data, decoder_name, args)
      File "c:\python25\lib\site-packages\PIL\Image.py", line 575, in fromstring
        raise ValueError("not enough image data")
    ValueError: not enough image data
    

    我应该如何形成 frombuffer 调用以16位模式工作?另外,如何使此函数在任何位深度模式下工作,而不是说必须将其作为参数传递?

    更新:来自 this question 我知道我必须使用“BGR;16”而不是“BGRX”作为第二模式参数。它拍摄正确的图片,或者指定步幅,或者不指定步幅。问题是某些值上的像素值稍有偏差:

    x   y native           ImageGrab
    280 0  (213, 210, 205) (214, 211, 206)
    280 20 (156, 153, 156) (156, 154, 156)
    280 40 (213, 210, 205) (214, 211, 206)
    300 0  (213, 210, 205) (214, 211, 206)
    

    只是从同一窗口获取的值的样本。屏幕截图看起来和肉眼一模一样,但我必须做一些像素操作。。我想使用本机方法的另一个原因是,它有点快,而且在具有双监视器的虚拟机中运行时性能更好。。(是的,我知道这很随机的复杂)。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Mark Ransom    13 年前

    对于 stride 参数,需要以字节为单位指定行大小。你的像素是16位,所以你可能天真地假设 stride = 2*bmpinfo['bmWidth'] ;不幸的是,Windows添加了填充,使步幅为32位的偶数倍。这意味着您必须将其舍入到4的次高倍数: stride = (stride + 3) / 4) * 4 .

    这个 documentation 没有提到16位原始格式,所以您必须检查Unpack.c模块,看看有什么可用的。

    最后你会注意到的是Windows喜欢把它的位图颠倒过来。

    编辑: 最后一个小问题很容易解释-从16位到24位的转换没有精确定义,两个不同转换之间的差分是完全正常的。转换数据后调整数据并不困难,因为我确信基于值的差异是恒定的。