Quickly getting the color of some pixels on the screen in Python on Windows 7
Question:
I need to get the color of some pixels on the screen or from the active window, and I need to do so quickly. I’ve tried using win32gui and ctypes/windll, but they’re much too slow. Each of these programs gets the color of 100 pixels:
import win32gui
import time
time.clock()
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = win32gui.GetPixel(win32gui.GetDC(win32gui.GetActiveWindow()), x , y)
print(time.clock())
and
from ctypes import windll
import time
time.clock()
hdc = windll.user32.GetDC(0)
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = windll.gdi32.GetPixel(hdc, x, y)
print(time.clock())
Each of these takes about 1.75 seconds. I need a program like this to take less than 0.1 seconds. What’s making it so slow?
I’m working with Python 3.x and Windows 7. If your solution requires I use Python 2.x, please link me to an article showing how to have Python 3.x and 2.x both installed. I looked, but couldn’t figure out how to do this.
Answers:
Thanks to Margus’ direction, I focused on getting the image before extracting the pixel information. Here’s a workable solution using the Python Imaging Library (PIL), which requires Python 2.x.
import ImageGrab
import time
time.clock()
image = ImageGrab.grab()
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = image.getpixel((x, y))
print(time.clock())
I don’t think it gets any simpler than that. This takes (on average) 0.1 seconds, which is a little slower than I’d like but fast enough.
As for having Python 3.x and 2.x both installed, I separated that into a new question. I’m still having some trouble with it, but it’s generally working.
This is better than using getpixel
all the time and works faster.
import ImageGrab
px = ImageGrab.grab().load()
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = px[x, y]
Reference: Image.load
Disabling Windows Desktop Composition speeds pixel up reading A LOT.
Computer -> Properties -> Advanced system settings -> Performance -> desktop composition [ ] (warning this disables Windows’s transparency effects)
Python 2.7 (Should be same for 3.x)
win32gui.GetPixel() #1.75s => 20ms
ctypes.windll.gdi32.GetPixel() #1.75s => 3ms (fastest)
image.getpixel() # 0.1s => 50ms
px[] # 0.1s => 50ms
AutoIt for comparison
$timer = TimerInit()
For $x = 0 To 100 Step 10
For $y = 0 To 100 Step 10
PixelGetColor($x,$y) ;slow => 1ms
Next
Next
ConsoleWrite("Time: " & TimerDiff($timer)/1000 & @CRLF)
try using the pyautogui library
import pyautogui
r, g, b = pyautogui.pixel(x, y)
print("The cursor is currently at: " + str(x) + ", " + str(y))
I need to get the color of some pixels on the screen or from the active window, and I need to do so quickly. I’ve tried using win32gui and ctypes/windll, but they’re much too slow. Each of these programs gets the color of 100 pixels:
import win32gui
import time
time.clock()
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = win32gui.GetPixel(win32gui.GetDC(win32gui.GetActiveWindow()), x , y)
print(time.clock())
and
from ctypes import windll
import time
time.clock()
hdc = windll.user32.GetDC(0)
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = windll.gdi32.GetPixel(hdc, x, y)
print(time.clock())
Each of these takes about 1.75 seconds. I need a program like this to take less than 0.1 seconds. What’s making it so slow?
I’m working with Python 3.x and Windows 7. If your solution requires I use Python 2.x, please link me to an article showing how to have Python 3.x and 2.x both installed. I looked, but couldn’t figure out how to do this.
Thanks to Margus’ direction, I focused on getting the image before extracting the pixel information. Here’s a workable solution using the Python Imaging Library (PIL), which requires Python 2.x.
import ImageGrab
import time
time.clock()
image = ImageGrab.grab()
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = image.getpixel((x, y))
print(time.clock())
I don’t think it gets any simpler than that. This takes (on average) 0.1 seconds, which is a little slower than I’d like but fast enough.
As for having Python 3.x and 2.x both installed, I separated that into a new question. I’m still having some trouble with it, but it’s generally working.
This is better than using getpixel
all the time and works faster.
import ImageGrab
px = ImageGrab.grab().load()
for y in range(0, 100, 10):
for x in range(0, 100, 10):
color = px[x, y]
Reference: Image.load
Disabling Windows Desktop Composition speeds pixel up reading A LOT.
Computer -> Properties -> Advanced system settings -> Performance -> desktop composition [ ] (warning this disables Windows’s transparency effects)
Python 2.7 (Should be same for 3.x)
win32gui.GetPixel() #1.75s => 20ms
ctypes.windll.gdi32.GetPixel() #1.75s => 3ms (fastest)
image.getpixel() # 0.1s => 50ms
px[] # 0.1s => 50ms
AutoIt for comparison
$timer = TimerInit()
For $x = 0 To 100 Step 10
For $y = 0 To 100 Step 10
PixelGetColor($x,$y) ;slow => 1ms
Next
Next
ConsoleWrite("Time: " & TimerDiff($timer)/1000 & @CRLF)
try using the pyautogui library
import pyautogui
r, g, b = pyautogui.pixel(x, y)
print("The cursor is currently at: " + str(x) + ", " + str(y))