0

I am currently working on a project where I need to take a 30x40 pixels screenshot from a specific area of my screen. This is not very hard to do as there are plenty of methods that do that.

The issue I have is that I need to take about 10 to 15 screenshots/second of the size I mentioned. When I looked at some of these methods that capture the screen, I have seen that when you give them parameters for a smaller selection, there's cropping involved. So a full screenshot is being taken, then the method crops it to the given size. That seems like a waste of resources if I'm only going to use 30x40 image, especially considering I will take thousands of screenshots.

So my question is: Is there a method that ONLY captures a part of the screen without capturing the whole screen cutting the desired section out of the big screenshot? I'm currently using this command:

im = pyautogui.screenshot(region=(0,0, 30, 40)).

Claudio
  • 7,474
  • 3
  • 18
  • 48
yoxhall
  • 66
  • 1
  • 7
  • 2
    Don't prematurely optimize unless you need to. If it works then don't worry about it. if it's too slow or hogs too many resources then start looking into other options. There are probably plenty of low-level ways, in native code, to do this optimally by, like, reading the screen buffer or whatever. – Random Davis May 27 '22 at 20:53
  • As @RandomDavis said, if you need to do it in a super-fast manner, you're probably going to need a lower level langue, like C for instance. You could write a C code to capture de screen buffer and save it as an image, and you could wrap this function into your python code. But I don't believe this is going to be a trivial task, you're probably going to need to dive deeper into each of the steps I mentioned. – Renan Klehm May 27 '22 at 21:00
  • when you ask to be recommended a library, which is off-topic, then at least **list the ones you found so far** and what's wrong with them. don't tell me you only found pyautogui. there are at least 1-2 more. – Christoph Rackwitz May 27 '22 at 23:04
  • By the way: "If speed is an issue, Python is not the solution ..." – Claudio May 27 '22 at 23:16
  • @ChristophRackwitz you are not wrong. This is my second question on StackOverflow so i'll gladly take constructive criticism on how to ask pertinent questions. Will take this into consideration next time i'll be asking a question. Thank you. – yoxhall May 27 '22 at 23:17
  • Thank you @Claudio. All i'm trying to do is detect when certain pixels in a certain part of the screen change colour so it can trigger an event. – yoxhall May 27 '22 at 23:26
  • 1
    @Claudio if speed is an issue, python is not out of the race. people just need to know how to use it right. there's `numba`, libraries for CUDA and OpenCL and MPI, ... "python is slow" is a half-lie to tell beginners so they stop NIH and start using the available libraries. – Christoph Rackwitz May 28 '22 at 10:03

1 Answers1

5

The Python mss module ( https://github.com/BoboTiG/python-mss , https://python-mss.readthedocs.io/examples.html ), an ultra fast cross-platform multiple screenshots module in pure Python using ctypes ( where MSS stands for Multiple Screen Shots ), is what you are looking for. The screenshots are fast enough to capture frames from a video and the smaller the part of the screen to grab the faster the capture (so there is apparently no cropping involved ). Check it out. mss.mss().grab() outperforms by far PIL.ImageGrab.grab(). Below a code example showing how to get the data of the screenshot pixels (allows to detect changes):

import mss
from time import perf_counter as T
left  = 0
right = 2
top   = 0
btm   = 2 

with mss.mss() as sct:
    # parameter for sct.grab() can be: 
    monitor = sct.monitors[1]         # entire screen
    bbox    = (left, top, right, btm) # screen part to capture

    sT=T()
    sct_im = sct.grab(bbox) # type: <class 'mss.screenshot.ScreenShot'>
    eT=T();print(" >", eT-sT) #  > 0.0003100260073551908

    print(len(sct_im.raw), sct_im.raw) 
    # 16 bytearray(b'-12\xff\x02DU\xff-12\xff"S_\xff')
    
    print(len(sct_im.rgb), sct_im.rgb) 
    # 12 b'21-UD\x0221-_S"'
Claudio
  • 7,474
  • 3
  • 18
  • 48