0

I'm on ubuntu and I want to check every 0.1sec the color of a specific pixel on my screen. How can I do that?

I know about PIL but this would need a full screenshot every 0.1sec just for one single pixel.

Then I found this method using ctypes.windll : Faster method of reading screen pixel in Python than PIL?

But this wont work because I'm not on Windows. Any other idea?

Edit: Solved thanks to b_c

from Xlib import display, X
from PIL import Image #PIL


def getColor(x,y):
    W, H = 1, 1
    dsp = display.Display()
    root = dsp.screen().root
    raw = root.get_image(x, y, W, H, X.ZPixmap, 0xffffffff)
    image = Image.frombytes("RGB", (W, H), raw.data, "raw", "BGRX")
    print image.getpixel((0, 0))
    time.sleep(0.01)
noxus Nexus
  • 63
  • 1
  • 5
  • 1
    There's a [python-xlib](https://github.com/python-xlib/python-xlib) package that was suggested on the [ubuntu forums](https://ubuntuforums.org/showthread.php?t=715256). I don't know anywhere near enough of X.Org to be able to tell if you can get the pixel values using it, but that was one of OP's goals in that post at least. – b_c Nov 07 '19 at 22:38
  • Possible duplicate of [How can I grab the color of a pixel on my desktop? (Linux)](https://stackoverflow.com/questions/1605350/how-can-i-grab-the-color-of-a-pixel-on-my-desktop-linux) – ItayMiz Nov 07 '19 at 22:50
  • This is a great working way. – noxus Nexus Nov 07 '19 at 22:51

3 Answers3

4

PIL and other similar programs usually allow you to specify a boundary box to grab smaller amounts

PyAutoGui allows you to take smaller sections

as referenced here https://pyautogui.readthedocs.io/en/latest/screenshot.html code such as

pyautogui.screenshot(region=(0,0, 300, 400))

could be useful

https://pillow.readthedocs.io/en/4.2.x/reference/Image.html

could be useful as well, bbox allows you to only observe a small area.

martineau
  • 112,593
  • 23
  • 157
  • 280
AlbinoRhino
  • 421
  • 4
  • 21
1

raw.data is sometimes returned as a string, for example when the color is black. This causes a:

TypeError: a bytes-like object is required, not 'str'

A dirty workaround for the code you posted is:

from Xlib import display, X
from PIL import Image #PIL

def getColor(x,y):
    W, H = 1, 1
    dsp = display.Display()
    root = dsp.screen().root
    raw = root.get_image(x, y, W, H, X.ZPixmap, 0xffffffff)
    if isinstance(raw.data,str):
        bytes=raw.data.encode()
    else:
        bytes=raw.data
    image = Image.frombytes("RGB", (W, H), bytes, "raw", "BGRX")
    print image.getpixel((0, 0))
    time.sleep(0.01)
Steve V.
  • 463
  • 4
  • 14
0

Hi I know how to solve your problem. I created a script which loops checking if the pixel or pixels change color.

This script uses only PIL to do this.

The time it takes to do its verification is 33ms.

Because that 33 or 32ms is the time it takes to capture the screen, so no matter how many pixels you need to check, the time will always be 33ms. Unfortunately I haven't found any other package that is faster.

import time
import keyboard
from PIL import Image, ImageGrab


while not keyboard.is_pressed('ctrl'): # press ctrl to stop.
    start_time = time.time()

    px = ImageGrab.grab().load()
    color1 = px[439, 664] # pixel 1
    color2 = px[575, 664] # pixel 2
    color3 = px[706, 664] # pixel 3
    color4 = px[842, 664] # pixel 4
    
    print(color1)

    print(f"Finish in: {round(1000 * (time.time() - start_time))} ms ") # how much  he takes to finish
Lotexiu
  • 1
  • 1