-
Notifications
You must be signed in to change notification settings - Fork 55
/
AdaBoost.py
122 lines (94 loc) · 4.99 KB
/
AdaBoost.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
from functools import partial
import numpy as np
from violajones.HaarLikeFeature import HaarLikeFeature
from violajones.HaarLikeFeature import FeatureTypes
import progressbar
from multiprocessing import Pool
LOADING_BAR_LENGTH = 50
# TODO: select optimal threshold for each feature
# TODO: attentional cascading
def learn(positive_iis, negative_iis, num_classifiers=-1, min_feature_width=1, max_feature_width=-1, min_feature_height=1, max_feature_height=-1):
"""
Selects a set of classifiers. Iteratively takes the best classifiers based
on a weighted error.
:param positive_iis: List of positive integral image examples
:type positive_iis: list[numpy.ndarray]
:param negative_iis: List of negative integral image examples
:type negative_iis: list[numpy.ndarray]
:param num_classifiers: Number of classifiers to select, -1 will use all
classifiers
:type num_classifiers: int
:return: List of selected features
:rtype: list[violajones.HaarLikeFeature.HaarLikeFeature]
"""
num_pos = len(positive_iis)
num_neg = len(negative_iis)
num_imgs = num_pos + num_neg
img_height, img_width = positive_iis[0].shape
# Maximum feature width and height default to image width and height
max_feature_height = img_height if max_feature_height == -1 else max_feature_height
max_feature_width = img_width if max_feature_width == -1 else max_feature_width
# Create initial weights and labels
pos_weights = np.ones(num_pos) * 1. / (2 * num_pos)
neg_weights = np.ones(num_neg) * 1. / (2 * num_neg)
weights = np.hstack((pos_weights, neg_weights))
labels = np.hstack((np.ones(num_pos), np.ones(num_neg) * -1))
images = positive_iis + negative_iis
# Create features for all sizes and locations
features = _create_features(img_height, img_width, min_feature_width, max_feature_width, min_feature_height, max_feature_height)
num_features = len(features)
feature_indexes = list(range(num_features))
num_classifiers = num_features if num_classifiers == -1 else num_classifiers
print('Calculating scores for images..')
votes = np.zeros((num_imgs, num_features))
bar = progressbar.ProgressBar()
# Use as many workers as there are CPUs
pool = Pool(processes=None)
for i in bar(range(num_imgs)):
votes[i, :] = np.array(list(pool.map(partial(_get_feature_vote, image=images[i]), features)))
# select classifiers
classifiers = []
print('Selecting classifiers..')
bar = progressbar.ProgressBar()
for _ in bar(range(num_classifiers)):
classification_errors = np.zeros(len(feature_indexes))
# normalize weights
weights *= 1. / np.sum(weights)
# select best classifier based on the weighted error
for f in range(len(feature_indexes)):
f_idx = feature_indexes[f]
# classifier error is the sum of image weights where the classifier
# is right
error = sum(map(lambda img_idx: weights[img_idx] if labels[img_idx] != votes[img_idx, f_idx] else 0, range(num_imgs)))
classification_errors[f] = error
# get best feature, i.e. with smallest error
min_error_idx = np.argmin(classification_errors)
best_error = classification_errors[min_error_idx]
best_feature_idx = feature_indexes[min_error_idx]
# set feature weight
best_feature = features[best_feature_idx]
feature_weight = 0.5 * np.log((1 - best_error) / best_error)
best_feature.weight = feature_weight
classifiers.append(best_feature)
# update image weights
weights = np.array(list(map(lambda img_idx: weights[img_idx] * np.sqrt((1-best_error)/best_error) if labels[img_idx] != votes[img_idx, best_feature_idx] else weights[img_idx] * np.sqrt(best_error/(1-best_error)), range(num_imgs))))
# remove feature (a feature can't be selected twice)
feature_indexes.remove(best_feature_idx)
return classifiers
def _get_feature_vote(feature, image):
return feature.get_vote(image)
def _create_features(img_height, img_width, min_feature_width, max_feature_width, min_feature_height, max_feature_height):
print('Creating haar-like features..')
features = []
for feature in FeatureTypes:
# FeatureTypes are just tuples
feature_start_width = max(min_feature_width, feature[0])
for feature_width in range(feature_start_width, max_feature_width, feature[0]):
feature_start_height = max(min_feature_height, feature[1])
for feature_height in range(feature_start_height, max_feature_height, feature[1]):
for x in range(img_width - feature_width):
for y in range(img_height - feature_height):
features.append(HaarLikeFeature(feature, (x, y), feature_width, feature_height, 0, 1))
features.append(HaarLikeFeature(feature, (x, y), feature_width, feature_height, 0, -1))
print('..done. ' + str(len(features)) + ' features created.\n')
return features