ImageGrab.grab() method is too slow

前端 未结 3 515
天涯浪人
天涯浪人 2021-01-06 01:44

So i need to get a bunch of screenshots every second, like 5. I am using it to program a bot for a game. However imagegrab method takes like 0.3 seconds, which is terribly s

相关标签:
3条回答
  • 2021-01-06 02:20

    So how I got it working for me is by using

    os.system("screencapture -R0,0,100,100 filename.png")
    im = Image.open("filename.png")
    

    Where you can replace 0,0,100,100 accordingly. It had a run time of less than 0.1s, more like 0.06s.

    0 讨论(0)
  • 2021-01-06 02:23

    Question : what could preform better than ImageGrab.grab() on a Mac

    I did a test between mss, pil, and pyscreenshot and measured the average time it took to take a various sized image grabs and reported the time in milliseconds.

    Answer

    It appears that mss far exceeds the others on a mac. To capture a 800x400 slice of the screen mms takes 15ms whereas the other two take 300-400ms. That's the difference between 66fps for mms or 3fps for the other two.

    Code

    # !pip install image
    # !pip install opencv-python
    # !pip install pyscreenshot
    
    import numpy as np
    from time import time
    
    
    resolutions = [
        (0, 0, 100,100),(0, 0, 200,100),
        (0, 0, 200,200),(0, 0, 400,200),
        (0, 0, 400,400),(0, 0, 800,400)
    ]
    
    
    import numpy as np
    import pyscreenshot as ImageGrab
    import cv2
    
    
    def show(nparray):
        import cv2
        cv2.imshow('window',cv2.cvtColor(nparray, cv2.COLOR_BGR2RGB))
        # key controls in a displayed window
        # if cv2.waitKey(25) & 0xFF == ord('q'):
            # cv2.destroyAllWindows()
    
    
    def mss_test(shape) :
        average = time()
        import mss
        sct = mss.mss()
        mon = {"top": shape[0], "left": shape[1], "width": shape[2]-shape[1], "height": shape[3]-shape[0]}
        for _ in range(5):
            printscreen =  np.asarray(sct.grab(mon))
        average_ms = int(1000*(time()-average)/5.)
        return average_ms, printscreen.shape
    
    
    
    
    def pil_test(shape) :
        average = time()
        from PIL import ImageGrab
        for _ in range(5):
            printscreen =  np.array(ImageGrab.grab(bbox=shape))
        average_ms = int(1000*(time()-average)/5.)
        return average_ms, printscreen.shape
    
    
    
    
    def pyscreenshot_test(shape):
        average = time()
        import pyscreenshot as ImageGrab
        for _ in range(5):
            printscreen = np.asarray( ImageGrab.grab(bbox=shape) )
        average_ms = int(1000*(time()-average)/5.)
        return average_ms, printscreen.shape
    
    
    named_function_pair = zip("mss_test,pil_test,pyscreenshot_test".split(","),
        [mss_test,pil_test,pyscreenshot_test])
    
    for name,function in named_function_pair:
        results = [ function(res) for res in resolutions ]
        print("Speed results for using",name)
        for res,result in zip(resolutions,results) :
            speed,shape = result
            print(res,"took",speed,"ms, produced shaped",shape)
    
    

    Output

    Speed results for using mss_test
    (0, 0, 100, 100) took 7 ms, produced shaped (200, 200, 4)
    (0, 0, 200, 100) took 4 ms, produced shaped (200, 400, 4)
    (0, 0, 200, 200) took 5 ms, produced shaped (400, 400, 4)
    (0, 0, 400, 200) took 6 ms, produced shaped (400, 800, 4)
    (0, 0, 400, 400) took 9 ms, produced shaped (800, 800, 4)
    (0, 0, 800, 400) took 15 ms, produced shaped (800, 1600, 4)
    
    Speed results for using pil_test
    (0, 0, 100, 100) took 313 ms, produced shaped (100, 100, 4)
    (0, 0, 200, 100) took 321 ms, produced shaped (100, 200, 4)
    (0, 0, 200, 200) took 334 ms, produced shaped (200, 200, 4)
    (0, 0, 400, 200) took 328 ms, produced shaped (200, 400, 4)
    (0, 0, 400, 400) took 321 ms, produced shaped (400, 400, 4)
    (0, 0, 800, 400) took 320 ms, produced shaped (400, 800, 4)
    
    Speed results for using pyscreenshot_test
    (0, 0, 100, 100) took 85 ms, produced shaped (200, 200, 4)
    (0, 0, 200, 100) took 101 ms, produced shaped (200, 400, 4)
    (0, 0, 200, 200) took 122 ms, produced shaped (400, 400, 4)
    (0, 0, 400, 200) took 163 ms, produced shaped (400, 800, 4)
    (0, 0, 400, 400) took 236 ms, produced shaped (800, 800, 4)
    (0, 0, 800, 400) took 400 ms, produced shaped (800, 1600, 4)
    
    

    Further Observations

    Although all three libraries were sent identical screen areas to grab, both mss and pyscreenshot grabbed physical pixels of the mac screen where as pil grabbed the logical pixels. This only happens if you have your Mac display resolution turned down from its highest resolution. In my case I have a retinal display set to "balanced" which means that each logical pixel is actually 2x2 physical pixels.

    0 讨论(0)
  • 2021-01-06 02:26

    Another solution is to use Python MSS.

    from mss import mss
    from PIL import Image
    
    def capture_screenshot():
        # Capture entire screen
        with mss() as sct:
            monitor = sct.monitors[1]
            sct_img = sct.grab(monitor)
            # Convert to PIL/Pillow Image
            return Image.frombytes('RGB', sct_img.size, sct_img.bgra, 'raw', 'BGRX')
    
    img = capture_screenshot()
    img.show()
    

    This function can return screenshots at up to 27 fps on my slow laptop.

    0 讨论(0)
提交回复
热议问题