'How to get the color of a pixel in python as fast as possible?
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)
Solution 1:[1]
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.
Solution 2:[2]
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)
Solution 3:[3]
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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | martineau |
Solution 2 | Steve V. |
Solution 3 |