ある画像が別の画像の一部かどうか調べるコードを書く

ある画像が別の画像の一部かどうか調べたい。
すぐに思いついたアルゴリズムをコードにする。
# pip install Pillow

path0 = 'large.png'
path1 = 'small.png'

NUM_LIMIT = 10

from PIL import Image,ImageChops

def is_int(v):
	return str(int(v))+'.0'==str(v)

def is_regular(rate,size):
	for i,v in enumerate(size):
		if is_int(v): size[i] = int(v)
		else: return None
	return size

def resize(size,im):
	return im.resize(tuple(size),Image.NEAREST)

def search(im0,im1):
	candidates = []
	size0 = im0.size
	size1 = im1.size
	for x in range(size0[0]-size1[0]):
		for y in range(size0[1]-size1[1]):
			im = im0.crop((x,y,x+size1[0],y+size1[1]))
			if ImageChops.difference(im,im1).getbbox() is None: candidates.append((x,y))
			if len(candidates)>NUM_LIMIT: exit('[ERROR] Too many candidates.')
	return candidates

def is_matched(pos,im0,im1):
	size1 = im1.size
	im = im0.crop((pos[0],pos[1],pos[0]+size1[0],pos[1]+size1[1]))
	return ImageChops.difference(im,im1).getbbox() is None

def get_candidates(rate,candidates):
	return [(int(x[0]*rate),int(x[1]*rate)) for x in candidates]


im0 = Image.open(path0)
size0 = im0.size

im1 = Image.open(path1)
size1 = im1.size

candidates = []
rate = 2048
while True:
	rate /= 2
	if rate < 1: break
	size0_resized = is_regular(rate,[x/rate for x in size0])
	if size0_resized is None: continue
	size1_resized = is_regular(rate,[x/rate for x in size1])
	if size1_resized is None: continue
	im0_resized = resize(size0_resized,im0)
	im1_resized = resize(size1_resized,im1)
	if len(candidates)==0: candidates = search(im0_resized,im1_resized)
	else: candidates = [x for x in candidates if is_matched(x,im0_resized,im1_resized)]
	#if len(candidates)==1: break # Just to get the candidate quickly
	candidates = get_candidates(2,candidates)

candidates = get_candidates(rate,candidates)
print('[INFO] {} found'.format(len(candidates)))
print(candidates)
small.pngがlarge.pngに含まれているかを調べる。
small.pngが1色のみの画像のように候補が多すぎる場合はexitで終了する。
このアルゴリズムは調べられる画像に制約がある。
リサイズを行うため、色の情報が変わってしまうと正しく判定できない。
2019/12/07 17:34
タグ