ある画像が別の画像の一部かどうか調べるコードを書く
ある画像が別の画像の一部かどうか調べたい。
すぐに思いついたアルゴリズムをコードにする。
# 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