4

I have a screenshot and I need to find some image (always the same size, rotation angle etc.) on it. I've found some solutions with PIL and numpy, but they only work for non-transparent images. I have to find something like a circle, so I have to use transparent background behind it.

The sample image looks like:

enter image description here

and I'm looking for a target like:

enter image description here

Any ideas how can I achieve this?

Hooked
  • 84,485
  • 43
  • 192
  • 261
mopsiok
  • 575
  • 1
  • 10
  • 19
  • Can you please add a sample image, your code and expected result. – alko Nov 29 '13 at 18:56
  • I tried using code from http://stackoverflow.com/questions/3049370/how-to-find-an-image-within-another-image-using-python but I got an error: if test.all(): AttributeError: 'bool' object has no attribute 'all' Actually I realized I can use normal rectangular image instead of round one and transparent background. Here's an example screenshot and image I want to find: http://mopsiok.comuv.com/uploader/screen_.png and http://mopsiok.comuv.com/uploader/cookie.png. – mopsiok Nov 29 '13 at 19:09
  • I don't see any reference to transparency in the question. Is the title misleading or did I miss something? – kraftydevil May 19 '19 at 21:16

2 Answers2

3

Since you are matching the image exactly, it's easy to create a sliding block to find the target. This isn't the fastest solution, but it's easy to get working.

import numpy as np
from scipy.misc import imread

screen = imread("screen.png")
target = imread("cookie.png")

def find_match(screen, target):
    dx,dy,_ = target.shape

    for x in xrange(screen.shape[0]-dx):
        for y in xrange(screen.shape[1]-dy):
            diff = (screen[x:x+dx,y:y+dy,:]-target)
            dz = np.abs(diff).sum()
            if dz == 0: return x,y, dx, dy
    return None, None, None, None

x,y,dx,dy = find_match(screen, target)

# Show the result

import pylab as plt
plt.subplot(121)
plt.imshow(screen)

screen_sample = np.copy(screen)
screen_sample[x:x+dx,y:y+dy,:] = 0
plt.subplot(122)
plt.imshow(screen_sample)

plt.tight_layout()
plt.show()

enter image description here

Hooked
  • 84,485
  • 43
  • 192
  • 261
2

Thanks for reply! I analysed the topic I posted above once again and got some idea. Your code is simple, but it takes ~40s to execute. I've done this:

def search(screen, img):
sx, sy = screen.size
ix, iy = img.size
for xstart in range(sx - ix): 
    for ystart in range(sy - iy):
        #search for the pixel on the screen that equals the pixel at img[0:0]
        if img.getpixel((0,0)) == screen.getpixel((xstart, ystart)):
            match = 1 #temporary
            for x in range(ix): #check if first row of img is on this coords
                if img.getpixel((x,0)) <> screen.getpixel((xstart+x, ystart)):
                    match = 0 #if there's any difference, exit the loop
                    break 
            if match == 1: #otherwise, if this coords matches the first row of img
                for x in range(ix): 
                    for y in range(iy):
                        #check every pixel of the img
                        if img.getpixel((x,y)) <> screen.getpixel((xstart+x, ystart+y)):
                            match = 0 #any difference - break
                            break
                if match == 1: return (xstart, ystart) #return top-left corner coordinates
return (-1,-1) #or this, if not found

It uses getpixel method which is quite slow, but it executes in ~4s and I'm pretty glad of this. Thank you for targeting me!

Regards mopsiok

mopsiok
  • 575
  • 1
  • 10
  • 19
  • If the other solutions were helpful, it's standard practice to upvote them. If your answer was the one that works for you, by all means accept it! – Hooked Dec 06 '13 at 19:36