17
17
# You should have received a copy of the GNU Lesser General Public License
18
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
27
import opencv.adaptors
29
21
from xpresser.imagematch import ImageMatch
32
24
FILTER_MARGIN = 25 # %
34
DEBUG_PERFORMANCE = False
37
27
class OpenCVFinder(object):
39
29
def find(self, screen_image, area_image):
40
30
matches = self._find(screen_image, area_image, best_match=True)
42
matches.sort(key=lambda match: -match.similarity)
49
38
def _load_image(self, image):
50
39
if "opencv_image" not in image.cache:
51
40
if image.filename is not None:
52
opencv_image = opencv.highgui.cvLoadImage(image.filename)
41
opencv_image = SimpleCV.Image(image.filename)
53
42
elif image.array is not None:
54
# The adaptor function can't deal with the alpha channel.
55
array = image.array[:,:,:3]
56
opencv_image = opencv.adaptors.NumPy2Ipl(array)
43
opencv_image = image.array
58
45
raise RuntimeError("Oops. Can't load image.")
59
46
image.cache["opencv_image"] = opencv_image
62
49
return image.cache["opencv_image"]
64
51
def _find(self, screen_image, area_image, best_match=False):
67
screen = self._load_image(screen_image)
68
area = self._load_image(area_image)
70
print "LOADING IMAGES: %.5fs" % (time.time()-started)
72
result_width = screen.width - area.width + 1
73
result_height = screen.height - area.height + 1
74
result = opencv.cvCreateImage(opencv.cvSize(result_width, result_height),
75
opencv.IPL_DEPTH_32F, 1)
78
opencv.cvMatchTemplate(screen, area, result, opencv.CV_TM_CCORR_NORMED)
80
print "MATCHING: %.5fs" % (time.time()-started)
82
result = opencv.adaptors.Ipl2NumPy(result)
87
for y, x in numpy.argwhere(result >= area_image.similarity):
88
matches.append(ImageMatch(area_image, x, y, result[y, x]))
89
if best_match and result[y, x] == 1.0:
92
print "FINDING POSITIONS: %.5fs" % (time.time()-started)
52
source = self._load_image(screen_image)
53
template = self._load_image(area_image)
55
matches = source.findTemplate(template, method="CCOEFF_NORM")
57
for m in [m for m in matches if m.quality >= area_image.similarity]:
59
ImageMatch(area_image, m.x, m.y, m.quality))
60
if best_match and m.quality == 1.0:
94
63
x_margin = int(FILTER_MARGIN/100.0 * area_image.width)
95
64
y_margin = int(FILTER_MARGIN/100.0 * area_image.height)
99
matches = self._filter_nearby_positions(matches, x_margin, y_margin)
100
if DEBUG_PERFORMANCE:
101
print "FILTERING: %.5fs" % (time.time()-started)
66
results = self._filter_nearby_positions(results, x_margin, y_margin)
68
results.sort(key=lambda match: -match.similarity)
104
72
def _filter_nearby_positions(self, matches, x_margin, y_margin):
105
73
"""Remove nearby positions by taking the best one.
107
75
Doing this is necessary because around a good match there will
108
76
likely be other worse matches.