0

I have created a program in python using pyscreenshot which periodically takes a screenshot of a specific area of screen which will contain one of several pre-defined images. I am looking to load each of these images from file into a list and compare them with the screenshot to see which is currently displayed. Initially the files were created by screenshotting the images as they were on screen:

while True:

filenm = str(i) + ".png"
im=ImageGrab.grab(bbox=(680,640,735,690)) #accross, down
im.save(filenm)
time.sleep(1)
i = i + 1

Then when I attempt to compare them it always reports false:

image2 = Image.open("04.png")

im=ImageGrab.grab(bbox=(680,640,735,690)) #accross, down

if im == image2:
    print "TRUE"
else:
    print "FALSE"

However comparing two of the images saved to files works:

image = Image.open("03.png")
image2 = Image.open("04.png")

if image == image2:
    print "TRUE"
else:
    print "FALSE"

So my question is how do the images differ once loaded from file and how can I compare the 'live' screenshot with an image loaded from file?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Gareth France
  • 53
  • 3
  • 5

2 Answers2

1

It looks like when I use ImageGrab.grab(), a PIL.Image.Image object is created, where as Image.open() creates a PIL.pngImagePlugin.PngImageFile object. You don't want to be calling == on the actual objects, since there's no special semantics implemented for PIL images across comparing these two object types, and thus it just checks if they are the same objects in memory. Code I would use to compare the two images proper (using numpy) would look something like

import numpy as np
from PIL import Image

def image_compare(image_1, image_2):
    arr1 = np.array(image_1)
    arr2 = np.array(image_2)
    if arr1.shape != arr2.shape:
        return False
    maxdiff = np.max(np.abs(arr1 - arr2))
    return maxdiff == 0

def image_compare_file(filename_1, filename_2):
    im1 = Image.load(filename_1)
    im2 = Image.load(filename_2)
    return image_compare(im1, im2)

Here I take advantage of PIL images auto-casting to numpy ndarrays with np.array(). I then check that the dimensions match, and compute the max of the absolute error if they do. If this max is zero, the images are identical. Now you could just call

if image_compare_file('file1.png','file2.png'):
    pass # images in file are identical
else:
    pass # images differ

or

if image_compare(image1,image2):
    pass # images are identical
else:
    pass # images differ
csunday95
  • 1,279
  • 10
  • 18
  • This looks close to what I need but please remember that I am not looking to load two files for comparison as this would require saving one screenshot per second and loading the same comparison files over and over. I need to work with a PIL.Image.Image and a PIL.pngImagePlugin.PngImageFile as you put it. – Gareth France Aug 09 '17 at 02:46
0

You might be interested in using a perceptual diff tool which will let you quickly identify differences in the screenshots. imgdiff is a library that wraps a tool for this in Python. A simple version can probably be implemented with PIL's ImageChop, as in this answer:

import Image
import ImageChops

im1 = Image.open("splash.png")
im2 = Image.open("splash2.png")

diff = ImageChops.difference(im2, im1)

For more on perceptual diffing, check out Bret Slatkin's talk about using it for safe continuous deployment.

Luke Francl
  • 31,028
  • 18
  • 69
  • 91
  • Sounds good but how do I know the answer from this? Diff just seems to contain another image. – Gareth France Aug 09 '17 at 03:14
  • 1
    @GarethFrance it's an image, but it's more useful to think of it as a 2D array containing pixel-wise differences. You can convert the Image object to a numpy ndarray if you need to do some computation on it. For example, if the sum of all elements in `diff` is 0, then you know the two images were pixel perfect matches. – ahota Aug 09 '17 at 19:48