-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatcher.py
100 lines (81 loc) · 2.89 KB
/
matcher.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
#!/usr/bin/python
import abc
import numpy
import scipy.spatial
import sklearn.decomposition
import sklearn.preprocessing
class Matcher(object):
"""
Base class for Matchers.
A Matcher should takes an MxN matrix data with M samples in N dimensions
and find the closest matching sample to the ones passed for comparision.
"""
__metaclass__ = abc.ABCMeta
def __call__(self, image):
"""
Returns the result from the match method.
"""
return self.match(image)
@abc.abstractmethod
def match(self, image):
"""
Returns the index of the image in images closes matching the image.
"""
class MeanColorMatcher(Matcher):
"""
Compare by average of colors.
"""
def __init__(self, data, randomization=1):
self.__randomization = randomization
color_averages = [self.color_average(row) for row in data]
color_averages = numpy.array(color_averages) # convert to numpy array
self.__kd_tree = scipy.spatial.cKDTree(color_averages)
@staticmethod
def color_average(data):
# data is expected to be a flattened image, it should be:
# [R, G, B, R, G, B, ...]
averages = (data[0::3].mean(), data[1::3].mean(), data[2::3].mean())
return numpy.array(averages)
def match(self, data):
averages = self.color_average(data)
dist, indexes = self.__kd_tree.query(averages, k=self.__randomization)
if self.__randomization > 1:
index = numpy.random.choice(indexes.flatten())
else:
index = indexes.flatten()[0]
return index
class PCAMatcher(Matcher):
MAX_COMPONENT_COEFFICIENT = 0.5
def __init__(self, data, randomization=1):
"""
Takes an MxN matrix data with M samples in N dimensions.
"""
self.__randomization = randomization
# pull out into row vectors, stack and scale
self.__scaler = sklearn.preprocessing.StandardScaler()
data = self.__scaler.fit_transform(data)
# setup PCA and kd-tree
max_components = int(self.MAX_COMPONENT_COEFFICIENT * len(data))
self.__pca = sklearn.decomposition.PCA(n_components=max_components)
data = self.__pca.fit_transform(data)
self.__kd_tree = scipy.spatial.cKDTree(data)
# store data
self.__data = data
def match(self, data):
data = self.transform(data)
dist, indexes = self.__kd_tree.query(data, k=self.__randomization)
if self.__randomization > 1:
index = numpy.random.choice(indexes.flatten())
else:
index = indexes
return index
def transform(self, data):
data = self.__scaler.transform(data)
data = self.__pca.transform(data)
return data
@property
def components(self):
return self.__pca.components_
@property
def data(self):
return self.__data