Commit 2e1b2e8c authored by Jayke Meijer's avatar Jayke Meijer

Merge branch 'master' of github.com:taddeus/licenseplates

parents b23d56af f2678488
......@@ -15,9 +15,3 @@ images/BBB
images/Images
images/Infos
images/licenseplates
chars
learning_set
test_set
classifier
classifier-model
classifier-characters
*.dat
results.txt
from LocalBinaryPatternizer import LocalBinaryPatternizer
from LocalBinaryPatternizer import LocalBinaryPatternizer as LBP
class Character:
def __init__(self, value, corners, image, filename=None):
......@@ -7,7 +7,14 @@ class Character:
self.image = image
self.filename = filename
def get_feature_vector(self):
pattern = LocalBinaryPatternizer(self.image)
def get_single_cell_feature_vector(self):
if hasattr(self, 'feature'):
return
self.feature = LBP(self.image).single_cell_features_vector()
def get_feature_vector(self, cell_size=None):
pattern = LBP(self.image) if cell_size == None \
else LBP(self.image, cell_size)
return pattern.create_features_vector()
from svmutil import svm_train, svm_problem, svm_parameter, svm_predict, \
svm_save_model, svm_load_model
svm_save_model, svm_load_model, RBF
class Classifier:
def __init__(self, c=None, gamma=None, filename=None):
def __init__(self, c=None, gamma=None, filename=None, cell_size=12):
self.cell_size = cell_size
if filename:
# If a filename is given, load a model from the given filename
self.model = svm_load_model(filename)
......@@ -11,8 +13,8 @@ class Classifier:
raise Exception('Please specify both C and gamma.')
else:
self.param = svm_parameter()
self.param.kernel_type = 2 # Radial kernel type
self.param.C = c # Soft margin
self.param.kernel_type = RBF # Radial kernel type
self.param.gamma = gamma # Parameter for radial kernel
self.model = None
......@@ -28,10 +30,12 @@ class Classifier:
l = len(learning_set)
for i, char in enumerate(learning_set):
print 'Training "%s" -- %d of %d (%d%% done)' \
print 'Found "%s" -- %d of %d (%d%% done)' \
% (char.value, i + 1, l, int(100 * (i + 1) / l))
classes.append(float(ord(char.value)))
features.append(char.get_feature_vector())
#features.append(char.get_feature_vector())
char.get_single_cell_feature_vector()
features.append(char.feature)
problem = svm_problem(classes, features)
self.model = svm_train(problem, self.param)
......@@ -48,9 +52,12 @@ class Classifier:
return float(matches) / len(test_set)
def classify(self, character):
def classify(self, character, true_value=None):
"""Classify a character object, return its value."""
predict = lambda x: svm_predict([0], [x], self.model)[0][0]
prediction_class = predict(character.get_feature_vector())
true_value = 0 if true_value == None else ord(true_value)
#x = character.get_feature_vector(self.cell_size)
character.get_single_cell_feature_vector()
p = svm_predict([true_value], [character.feature], self.model)
prediction_class = int(p[0][0])
return chr(int(prediction_class))
return chr(prediction_class)
......@@ -18,19 +18,23 @@ class GrayscaleImage:
self.data = data
def __iter__(self):
self.__i_x = -1
self.__i_y = 0
return self
def next(self):
self.__i_x += 1
if self.__i_x == self.width:
self.__i_x = 0
self.__i_y += 1
if self.__i_y == self.height:
raise StopIteration
return self.__i_y, self.__i_x, self[self.__i_y, self.__i_x]
for y in xrange(self.data.shape[0]):
for x in xrange(self.data.shape[1]):
yield y, x, self.data[y, x]
#self.__i_x = -1
#self.__i_y = 0
#return self
#def next(self):
# self.__i_x += 1
# if self.__i_x == self.width:
# self.__i_x = 0
# self.__i_y += 1
# if self.__i_y == self.height:
# raise StopIteration
# return self.__i_y, self.__i_x, self[self.__i_y, self.__i_x]
def __getitem__(self, position):
return self.data[position]
......
......@@ -16,6 +16,12 @@ class Histogram:
def get_bin_index(self, number):
return (number - self.min) / ((self.max - self.min) / len(self.bins))
def normalize(self):
minimum = min(self.bins)
self.bins = map(lambda b: b - minimum, self.bins)
maximum = float(max(self.bins))
self.bins = map(lambda b: b / maximum, self.bins)
def intersect(self, other):
h1 = self.bins
h2 = other.bins
......
......@@ -6,34 +6,37 @@ class LocalBinaryPatternizer:
def __init__(self, image, cell_size=16):
self.cell_size = cell_size
self.image = image
self.setup_histograms()
def setup_histograms(self):
cells_in_width = int(ceil(self.image.width / float(self.cell_size)))
cells_in_height = int(ceil(self.image.height / float(self.cell_size)))
self.features = []
self.histograms = []
for i in xrange(cells_in_height):
self.features.append([])
self.histograms.append([])
for j in xrange(cells_in_width):
self.features[i].append(Histogram(256,0,256))
self.histograms[i].append(Histogram(256, 0, 256))
def create_features_vector(self):
''' Walk around the pixels in clokwise order, shifting 1 bit less
at each neighbour starting at 7 in the top-left corner. This gives a
8-bit feature number of a pixel'''
for y, x, value in self.image:
def local_binary_pattern(self, y, x, value):
return (self.is_pixel_darker(y - 1, x - 1, value) << 7) \
| (self.is_pixel_darker(y - 1, x , value) << 6) \
| (self.is_pixel_darker(y - 1, x + 1, value) << 5) \
| (self.is_pixel_darker(y , x + 1, value) << 4) \
| (self.is_pixel_darker(y + 1, x + 1, value) << 3) \
| (self.is_pixel_darker(y + 1, x , value) << 2) \
| (self.is_pixel_darker(y + 1, x - 1, value) << 1) \
| (self.is_pixel_darker(y , x - 1, value) << 0)
pattern = (self.is_pixel_darker(y - 1, x - 1, value) << 7) \
| (self.is_pixel_darker(y - 1, x , value) << 6) \
| (self.is_pixel_darker(y - 1, x + 1, value) << 5) \
| (self.is_pixel_darker(y , x + 1, value) << 4) \
| (self.is_pixel_darker(y + 1, x + 1, value) << 3) \
| (self.is_pixel_darker(y + 1, x , value) << 2) \
| (self.is_pixel_darker(y + 1, x - 1, value) << 1) \
| (self.is_pixel_darker(y , x - 1, value) << 0)
def create_features_vector(self):
'''Walk around the pixels in clokwise order, shifting 1 bit less at
each neighbour starting at 7 in the top-left corner. This gives a 8-bit
feature number of a pixel'''
self.setup_histograms()
for y, x, value in self.image:
cy, cx = self.get_cell_index(y, x)
self.features[cy][cx].add(pattern)
self.histograms[cy][cx].add(self.local_binary_pattern(y, x, value))
return self.get_features_as_array()
......@@ -44,4 +47,27 @@ class LocalBinaryPatternizer:
return (y / self.cell_size, x / self.cell_size)
def get_features_as_array(self):
return [h.bins for h in [h for sub in self.features for h in sub]][0]
f = []
# Concatenate all histogram bins
for row in self.histograms:
for hist in row:
f.extend(hist.bins)
return f
#return [h.bins for h in [h for sub in self.histograms for h in sub]][0]
def get_single_histogram(self):
"""Create a single histogram of the local binary patterns in the
image."""
h = Histogram(256, 0, 256)
for y, x, value in self.image:
h.add(self.local_binary_pattern(y, x, value))
h.normalize()
return h
def single_cell_features_vector(self):
return self.get_single_histogram().bins
......@@ -5,7 +5,8 @@ from GaussianFilter import GaussianFilter
class NormalizedCharacterImage(GrayscaleImage):
def __init__(self, image=None, data=None, size=(60, 40), blur=1.1, crop_threshold=0.9):
def __init__(self, image=None, data=None, size=(60, 40), blur=1.1, \
crop_threshold=0.9):
if image != None:
GrayscaleImage.__init__(self, data=deepcopy(image.data))
elif data != None:
......@@ -13,18 +14,17 @@ class NormalizedCharacterImage(GrayscaleImage):
self.blur = blur
self.crop_threshold = crop_threshold
self.size = size
self.gausse_filter()
self.gaussian_filter()
self.increase_contrast()
self.crop_to_letter()
self.resize()
#self.crop_to_letter()
#self.resize()
def increase_contrast(self):
self.data -= self.data.min()
self.data /= self.data.max()
self.data = self.data.astype(float) / self.data.max()
def gausse_filter(self):
filter = GaussianFilter(1.1)
filter.filter(self)
def gaussian_filter(self):
GaussianFilter(self.blur).filter(self)
def crop_to_letter(self):
cropper = LetterCropper(0.9)
......
C = [2 ** p for p in xrange(-5, 16, 2)]:
Y = [2 ** p for p in xrange(-15, 4, 2)]
best_result = 0
#!/usr/bin/python
from cPickle import load
from Classifier import Classifier
C = [float(2 ** p) for p in xrange(-5, 16, 2)]
Y = [float(2 ** p) for p in xrange(-15, 4, 2)]
best_classifier = None
learning_set = load(file('learning_set', 'r'))
test_set = load(file('test_set', 'r'))
print 'Loading learning set...'
learning_set = load(file('learning_set.dat', 'r'))
print 'Learning set:', [c.value for c in learning_set]
print 'Loading test set...'
test_set = load(file('test_set.dat', 'r'))
print 'Test set:', [c.value for c in test_set]
# Perform a grid-search on different combinations of soft margin and gamma
results = []
best = (0,)
i = 0
for c in C:
for y in Y:
classifier = Classifier(c=c, gamma=y)
classifier.train(learning_set)
result = classifier.test(test_set)
if result > best_result:
best_classifier = classifier
if result > best[0]:
best = (result, c, y, classifier)
results.append(result)
i += 1
print '%d of %d, c = %f, gamma = %f, result = %d%%' \
% (i, len(C) * len(Y), c, y, int(round(result * 100)))
i = 0
print '\n c\y',
for y in Y:
print '| %f' % y,
print
for c in C:
print ' %7s' % c,
for y in Y:
print '| %8d' % int(round(results[i] * 100)),
i += 1
print
print 'c = %f, gamma = %f, result = %d%%' % (c, y, int(result * 100))
print '\nBest result: %.3f%% for C = %f and gamma = %f' % best[:3]
best_classifier.save('best_classifier')
best[3].save('classifier.dat')
#!/usr/bin/python
from os import listdir
from cPickle import dump
from pylab import imshow, show
from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage
from Character import Character
c = []
for char in sorted(listdir('../images/LearningSet')):
for image in sorted(listdir('../images/LearningSet/' + char)):
f = '../images/LearningSet/' + char + '/' + image
image = GrayscaleImage(f)
norm = NormalizedCharacterImage(image, blur=1, size=(48, 36))
#imshow(norm.data, cmap='gray')
#show()
character = Character(char, [], norm)
character.get_single_cell_feature_vector()
c.append(character)
print char
dump(c, open('characters.dat', 'w+'))
......@@ -3,7 +3,7 @@ from pylab import subplot, show, imshow, axis
from cPickle import load
x, y = 25, 25
chars = load(file('chars', 'r'))[:(x * y)]
chars = load(file('characters.dat', 'r'))[:(x * y)]
for i in range(x):
for j in range(y):
......
#!/usr/bin/python
from pylab import subplot, show, imshow, axis
from cPickle import load
chars = filter(lambda c: c.value == 'A', load(file('chars', 'r')))
for i in range(10):
for j in range(3):
index = j * 10 + i
subplot(10, 3, index + 1)
axis('off')
imshow(chars[index].image.data, cmap='gray')
show()
......@@ -3,57 +3,56 @@ from xml_helper_functions import xml_to_LicensePlate
from Classifier import Classifier
from cPickle import dump, load
chars = []
for i in range(9):
for j in range(100):
try:
filename = '%04d/00991_%04d%02d' % (i, i, j)
print 'loading file "%s"' % filename
# is nog steeds een licensePlate object, maar die is nu heel anders :P
plate = xml_to_LicensePlate(filename)
if hasattr(plate, 'characters'):
chars.extend(plate.characters)
except:
print 'epic fail'
chars = load(file('characters.dat', 'r'))
learning_set = []
test_set = []
print 'loaded %d chars' % len(chars)
#s = {}
#
#for char in chars:
# if char.value not in s:
# s[char.value] = [char]
# else:
# s[char.value].append(char)
#
#for value, chars in s.iteritems():
# learning_set += chars[::2]
# test_set += chars[1::2]
dump(chars, file('chars', 'w+'))
#----------------------------------------------------------------
chars = load(file('chars', 'r'))[:500]
learned = []
learning_set = []
test_set = []
for char in chars:
if learned.count(char.value) > 12:
if learned.count(char.value) == 70:
test_set.append(char)
else:
learning_set.append(char)
learned.append(char.value)
#print 'Learning set:', [c.value for c in learning_set]
#print 'Test set:', [c.value for c in test_set]
dump(learning_set, file('learning_set', 'w+'))
dump(test_set, file('test_set', 'w+'))
print 'Learning set:', [c.value for c in learning_set]
print 'Test set:', [c.value for c in test_set]
print 'Saving learning set...'
dump(learning_set, file('learning_set.dat', 'w+'))
print 'Saving test set...'
dump(test_set, file('test_set.dat', 'w+'))
#----------------------------------------------------------------
learning_set = load(file('learning_set', 'r'))
print 'Loading learning set'
learning_set = load(file('learning_set.dat', 'r'))
# Train the classifier with the learning set
classifier = Classifier(c=30, gamma=1)
classifier = Classifier(c=512, gamma=.125, cell_size=12)
classifier.train(learning_set)
classifier.save('classifier')
classifier.save('classifier.dat')
print 'Saved classifier'
#----------------------------------------------------------------
classifier = Classifier(filename='classifier')
test_set = load(file('test_set', 'r'))
print 'Loading classifier'
classifier = Classifier(filename='classifier.dat')
print 'Loading test set'
test_set = load(file('test_set.dat', 'r'))
l = len(test_set)
matches = 0
for i, char in enumerate(test_set):
prediction = classifier.classify(char)
prediction = classifier.classify(char, char.value)
if char.value == prediction:
print ':-----> Successfully recognized "%s"' % char.value,
......
#!/usr/bin/python
from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage
......
......@@ -5,32 +5,39 @@ from GrayscaleImage import GrayscaleImage
from cPickle import load
from numpy import zeros, resize
chars = load(file('chars', 'r'))[::2]
chars = load(file('characters.dat', 'r'))[::2]
left = None
right = None
for c in chars:
if c.value == '8':
if left == None:
left = c.image
elif right == None:
right = c.image
else:
break
s = {}
size = 16
for char in chars:
if char.value not in s:
s[char.value] = [char]
else:
s[char.value].append(char)
left = s['F'][2].image
right = s['A'][0].image
size = 12
d = (left.size[0] * 4, left.size[1] * 4)
#GrayscaleImage.resize(left, d)
#GrayscaleImage.resize(right, d)
p1 = LocalBinaryPatternizer(left, size)
h1 = p1.get_single_histogram()
p1.create_features_vector()
p1 = p1.features
p2 = LocalBinaryPatternizer(right, size)
h2 = p2.get_single_histogram()
p2.create_features_vector()
p2 = p2.features
total_intersect = h1.intersect(h2)
s = (len(p1), len(p1[0]))
match = zeros(left.shape)
m = 0
......@@ -52,6 +59,7 @@ for y in range(s[0]):
m += intersect
print 'Match: %d%%' % int(m / (s[0] * s[1]) * 100)
print 'Single histogram instersection: %d%%' % int(total_intersect * 100)
subplot(311)
imshow(left.data, cmap='gray')
......
#!/usr/bin/python
from GaussianFilter import GaussianFilter
from GrayscaleImage import GrayscaleImage
......
#!/usr/bin/python
from Histogram import Histogram
his = Histogram(10, 10, 110)
......@@ -22,4 +23,4 @@ his.add(99)
his.add(100)
his.add(109)
print his.bins
\ No newline at end of file
print his.bins
#!/usr/bin/python
from GrayscaleImage import GrayscaleImage
from LocalBinaryPatternizer import LocalBinaryPatternizer
......
#!/usr/bin/python
from LetterCropper import LetterCropper
from GrayscaleImage import GrayscaleImage
......@@ -7,4 +8,4 @@ cropper = LetterCropper(image)
cropped_letter = cropper.get_cropped_letter()
cropped_letter.show()
\ No newline at end of file
cropped_letter.show()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment