2

python 3.6, Windows 10: I am trying to take one (partial) screenshot every 1-5 milliseconds to then run some custom OCR on it to extract some data. My code for taking the screenshots using the mss package takes between 16 and 47ms depending upon the number of pixels I try to capture.

I have 3 separate lines of questions:

1.) Is there an alternative to mss that is faster?

2.) Is there a way to speed up mss by factor 2-3?

3.) How can I find out via code profiling/cProfile output shown below how I can achieve performance improvements? The way I read the output is that a lot of time is spent in the "grab" function, but it's unclear what inside the grab function actually takes so long.

from mss import mss
import mss.tools as mss_tools
import cProfile, pstats, io

def profile(fnc):
    def inner(*args, **kwargs):
        pr = cProfile.Profile()
        pr.enable()
        retval = fnc(*args, **kwargs)
        pr.disable()
        s = io.StringIO()
        sortby = 'cumulative'
        ps = pstats.Stats(pr, stream=s).sort_stats(sortby)
        ps.print_stats()
        print(s.getvalue())
        return retval

    return inner

@profile
def main():
    with mss() as sct:
        for i in range(100):
            monitor = sct.monitors[1]
            left = monitor["left"]
            top = monitor["top"]
            right = left + 1
            lower = top + 1
            bbox = (left, top, right, lower)
            shot = sct.grab(bbox)
            # mss_tools.to_png(shot.rgb, shot.size, output='partialscreen.png') #no performance difference with or without this
            # sct.shot() #code takes much more time (almost factor 10 higher compared to taking a large share of the screen)

main()
Tiger-222
  • 6,677
  • 3
  • 47
  • 60
user2136502
  • 69
  • 1
  • 3

1 Answers1

3

I am the MSS developer :)

Completely impartially, I do not think there is faster than MSS. But if we can make it even faster, I am +1000 on that :)

A little improvement, not related to MSS, would be to move out vars from the for loop:

@profile
def main():
    with mss() as sct:
        monitor = sct.monitors[1]
        left = monitor["left"]
        top = monitor["top"]
        right = left + 1
        lower = top + 1
        bbox = (left, top, right, lower)
        for i in range(100):
            shot = sct.grab(bbox)

To measure what goes inside MSS.grab(), perhaps could you add the @profile onto the method in MSS. Ugly but for testing it is OK.

In that method, there are 2 things that may take time:

I am curious to know where the code is slower in the method.

Tiger-222
  • 6,677
  • 3
  • 47
  • 60