-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfindimg.py
executable file
·148 lines (132 loc) · 4.55 KB
/
findimg.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/env python3
from concurrent.futures import ThreadPoolExecutor
from PIL import Image
from file_finder import FileFinder, FileInfo
import argparse
import multiprocessing
import os
import subprocess
import sys
import tempfile
import threading
StandardImageSize = (608, 392)
num_cpus = max(1, multiprocessing.cpu_count())
stdout_lock = threading.Lock()
class InvalidOutputException(Exception):
pass
class Options(object):
def __init__(self):
self.island_symbol = None
self.image = None
def Parse(self):
desc = "Find the best matching game image to the one specified."
parser = argparse.ArgumentParser(description=desc)
parser.add_argument('-i', '--island',
help='Only look for image in the specified island.')
parser.add_argument('image', metavar='IMAGE', type=str,
help="The input image to find the best match to")
args = parser.parse_args()
self.image = args.image
if args.island:
self.island_symbol = args.island.upper()
class ImageMatcher(object):
def __init__(self, top_dir, island_symbol):
self.top_dir = top_dir
self.island_symbol = island_symbol
@staticmethod
def Compare(img, exemplar):
"""Compare |img| to |exemplar| and return a tuple of (RMSE, img)."""
cmd = ['compare', '-metric', 'RMSE', '-fuzz', '3%', img, exemplar, 'null']
p = subprocess.Popen(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE)
out = p.communicate()
for line in iter(out):
if not line:
continue
line = line.decode("utf-8")
items = line.split()
try:
rmse = float(items[0])
return (rmse, exemplar)
except ValueError as e:
with stdout_lock:
print('XXXXXXX Got error')
print(line)
raise InvalidOutputException()
@staticmethod
def TrimScreenshot(inname, outname):
"""Trims the margin of a screenshot.
This includes the window border, and black margin.
to disable the screenshot shadow.
http://apple.stackexchange.com/questions/50860/how-do-i-take-a-screenshot-without-the-shadow-behind-it
defaults write com.apple.screencapture disable-shadow -bool TRUE
Numbers currently hard-coded for macOS with retina screen."""
crop = {'left': 144, 'width': 1216, 'top': 184, 'height': 784}
with Image.open(inname) as im:
cropped = im.crop((crop['left'], crop['top'],
crop['left'] + crop['width'],
crop['top'] + crop['height']))
scaledimg = cropped.resize(StandardImageSize, Image.BICUBIC)
scaledimg.save(outname)
def FilterImage(self, info):
if self.island_symbol and self.island_symbol != info.island:
return True
if info.friendly_name() == 'black':
return True
with Image.open(info.file_path) as im:
return im.size != StandardImageSize
def LoadFiles(self, suffix):
images = []
finder = FileFinder()
for filename in finder.GetFiles(self.top_dir, suffix):
# Thumbnails are created by this program.
if 'thumbnail' in filename:
continue
dir_name = os.path.basename(os.path.dirname(filename))
if dir_name == 'b2_data-MHK' or dir_name == 'Extras-MHK':
continue
info = finder.ParseFilename(os.path.basename(filename))
info.file_path = filename
if self.FilterImage(info):
continue
images.append(info)
return images
def FindMatches(self, fname):
executor = ThreadPoolExecutor(max_workers=num_cpus)
futures = []
count = 0
for image in self.LoadFiles('png'):
count += 1
if count >= 10000:
break
futures.append(executor.submit(ImageMatcher.Compare,
fname, image.file_path))
results = []
for f in futures:
results.append(f.result())
with stdout_lock:
print('Analyzing image %d/%d (%.1f%%)' %
(len(results),
len(futures),
(len(results) * 100 / len(futures))), end='\r')
print()
results.sort(key=lambda result: result[0])
print('Top five maches')
for result in results[:5]:
print('%f: %s' % result)
print('Examined %d images using %d cores' % (count, num_cpus))
if __name__ == '__main__':
options = Options()
options.Parse()
tmp_name = 'Trimmed.png'
try:
os.unlink(tmp_name)
except:
pass
ImageMatcher.TrimScreenshot(options.image, tmp_name)
matcher = ImageMatcher(os.path.join('browser', 'protected', 'DVD'),
options.island_symbol)
matcher.FindMatches(tmp_name)
try:
os.unlink(tmp_name)
except:
pass