Commit 8c3cfd52 authored by Richard Torenvliet's avatar Richard Torenvliet

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

parents 2c68e580 df98d883
...@@ -172,11 +172,7 @@ order. Starting with dividing the pattern in to cells of size 16. ...@@ -172,11 +172,7 @@ order. Starting with dividing the pattern in to cells of size 16.
result is a feature vector of the image. result is a feature vector of the image.
\item Feed these vectors to a support vector machine. This will ''learn'' which \item Feed these vectors to a support vector machine. This will ''learn'' which
<<<<<<< HEAD
vector indicates what vector is which character. vector indicates what vector is which character.
=======
vectors indicate what letter.
>>>>>>> 2e1b2e8c8db4f802d203791a6f03eeca7d0aff70
\end{itemize} \end{itemize}
......
*.dat *.dat
results.txt results*.txt
...@@ -7,11 +7,12 @@ class Character: ...@@ -7,11 +7,12 @@ class Character:
self.image = image self.image = image
self.filename = filename self.filename = filename
def get_single_cell_feature_vector(self): def get_single_cell_feature_vector(self, neighbours=5):
if hasattr(self, 'feature'): if hasattr(self, 'feature'):
return return
self.feature = LBP(self.image).single_cell_features_vector() pattern = LBP(self.image, neighbours=neighbours)
self.feature = pattern.single_cell_features_vector()
def get_feature_vector(self, cell_size=None): def get_feature_vector(self, cell_size=None):
pattern = LBP(self.image) if cell_size == None \ pattern = LBP(self.image) if cell_size == None \
......
...@@ -3,8 +3,8 @@ from svmutil import svm_train, svm_problem, svm_parameter, svm_predict, \ ...@@ -3,8 +3,8 @@ from svmutil import svm_train, svm_problem, svm_parameter, svm_predict, \
class Classifier: class Classifier:
def __init__(self, c=None, gamma=None, filename=None, cell_size=12): def __init__(self, c=None, gamma=None, filename=None, neighbours=3):
self.cell_size = cell_size self.neighbours = neighbours
if filename: if filename:
# If a filename is given, load a model from the given filename # If a filename is given, load a model from the given filename
...@@ -34,7 +34,7 @@ class Classifier: ...@@ -34,7 +34,7 @@ class Classifier:
% (char.value, i + 1, l, int(100 * (i + 1) / l)) % (char.value, i + 1, l, int(100 * (i + 1) / l))
classes.append(float(ord(char.value))) classes.append(float(ord(char.value)))
#features.append(char.get_feature_vector()) #features.append(char.get_feature_vector())
char.get_single_cell_feature_vector() char.get_single_cell_feature_vector(self.neighbours)
features.append(char.feature) features.append(char.feature)
problem = svm_problem(classes, features) problem = svm_problem(classes, features)
...@@ -56,7 +56,7 @@ class Classifier: ...@@ -56,7 +56,7 @@ class Classifier:
"""Classify a character object, return its value.""" """Classify a character object, return its value."""
true_value = 0 if true_value == None else ord(true_value) true_value = 0 if true_value == None else ord(true_value)
#x = character.get_feature_vector(self.cell_size) #x = character.get_feature_vector(self.cell_size)
character.get_single_cell_feature_vector() character.get_single_cell_feature_vector(self.neighbours)
p = svm_predict([true_value], [character.feature], self.model) p = svm_predict([true_value], [character.feature], self.model)
prediction_class = int(p[0][0]) prediction_class = int(p[0][0])
......
...@@ -3,9 +3,13 @@ from math import ceil ...@@ -3,9 +3,13 @@ from math import ceil
class LocalBinaryPatternizer: class LocalBinaryPatternizer:
def __init__(self, image, cell_size=16): def __init__(self, image, cell_size=16, neighbours=3):
self.cell_size = cell_size self.cell_size = cell_size
self.image = image self.image = image
self.pattern_callback, self.bins = {
3: (self.pattern_3x3, 256),
5: (self.pattern_5x5, 4096)
}[neighbours]
def setup_histograms(self): def setup_histograms(self):
cells_in_width = int(ceil(self.image.width / float(self.cell_size))) cells_in_width = int(ceil(self.image.width / float(self.cell_size)))
...@@ -16,9 +20,9 @@ class LocalBinaryPatternizer: ...@@ -16,9 +20,9 @@ class LocalBinaryPatternizer:
self.histograms.append([]) self.histograms.append([])
for j in xrange(cells_in_width): for j in xrange(cells_in_width):
self.histograms[i].append(Histogram(256, 0, 256)) self.histograms[i].append(Histogram(self.bins, 0, self.bins))
def local_binary_pattern(self, y, x, value): def pattern_3x3(self, y, x, value):
return (self.is_pixel_darker(y - 1, x - 1, value) << 7) \ 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 , value) << 6) \
| (self.is_pixel_darker(y - 1, x + 1, value) << 5) \ | (self.is_pixel_darker(y - 1, x + 1, value) << 5) \
...@@ -26,7 +30,21 @@ class LocalBinaryPatternizer: ...@@ -26,7 +30,21 @@ class LocalBinaryPatternizer:
| (self.is_pixel_darker(y + 1, x + 1, value) << 3) \ | (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 , value) << 2) \
| (self.is_pixel_darker(y + 1, x - 1, value) << 1) \ | (self.is_pixel_darker(y + 1, x - 1, value) << 1) \
| (self.is_pixel_darker(y , x - 1, value) << 0) | (self.is_pixel_darker(y , x - 1, value))
def pattern_5x5(self, y, x, value):
return (self.is_pixel_darker(y - 1, x - 2, value) << 11) \
| (self.is_pixel_darker(y , x - 2, value) << 10) \
| (self.is_pixel_darker(y + 1, x - 2, value) << 9) \
| (self.is_pixel_darker(y + 2, x - 1, value) << 8) \
| (self.is_pixel_darker(y + 2, x , value) << 7) \
| (self.is_pixel_darker(y + 2, x + 1, value) << 6) \
| (self.is_pixel_darker(y + 1, x + 2, value) << 5) \
| (self.is_pixel_darker(y , x + 2, value) << 4) \
| (self.is_pixel_darker(y - 1, x + 2, value) << 3) \
| (self.is_pixel_darker(y - 2, x + 1, value) << 2) \
| (self.is_pixel_darker(y - 2, x , value) << 1) \
| (self.is_pixel_darker(y - 2, x - 1, value))
def create_features_vector(self): def create_features_vector(self):
'''Walk around the pixels in clokwise order, shifting 1 bit less at '''Walk around the pixels in clokwise order, shifting 1 bit less at
...@@ -36,7 +54,7 @@ class LocalBinaryPatternizer: ...@@ -36,7 +54,7 @@ class LocalBinaryPatternizer:
for y, x, value in self.image: for y, x, value in self.image:
cy, cx = self.get_cell_index(y, x) cy, cx = self.get_cell_index(y, x)
self.histograms[cy][cx].add(self.local_binary_pattern(y, x, value)) self.histograms[cy][cx].add(self.pattern_callback(y, x, value))
return self.get_features_as_array() return self.get_features_as_array()
...@@ -55,15 +73,14 @@ class LocalBinaryPatternizer: ...@@ -55,15 +73,14 @@ class LocalBinaryPatternizer:
f.extend(hist.bins) f.extend(hist.bins)
return f return f
#return [h.bins for h in [h for sub in self.histograms for h in sub]][0]
def get_single_histogram(self): def get_single_histogram(self):
"""Create a single histogram of the local binary patterns in the """Create a single histogram of the local binary patterns in the
image.""" image."""
h = Histogram(256, 0, 256) h = Histogram(self.bins, 0, self.bins)
for y, x, value in self.image: for y, x, value in self.image:
h.add(self.local_binary_pattern(y, x, value)) h.add(self.pattern_callback(y, x, value))
h.normalize() h.normalize()
......
...@@ -5,19 +5,22 @@ from GaussianFilter import GaussianFilter ...@@ -5,19 +5,22 @@ from GaussianFilter import GaussianFilter
class NormalizedCharacterImage(GrayscaleImage): class NormalizedCharacterImage(GrayscaleImage):
def __init__(self, image=None, data=None, size=(60, 40), blur=1.1, \ def __init__(self, image=None, data=None, height=None, blur=1.1):
crop_threshold=0.9):
if image != None: if image != None:
GrayscaleImage.__init__(self, data=deepcopy(image.data)) GrayscaleImage.__init__(self, data=deepcopy(image.data))
elif data != None: elif data != None:
GrayscaleImage.__init__(self, data=deepcopy(data)) GrayscaleImage.__init__(self, data=deepcopy(data))
self.blur = blur self.blur = blur
self.crop_threshold = crop_threshold
self.size = size
self.gaussian_filter() self.gaussian_filter()
self.increase_contrast() self.increase_contrast()
#self.crop_threshold = crop_threshold
#self.crop_to_letter() #self.crop_to_letter()
#self.resize()
self.height = height
self.resize()
def increase_contrast(self): def increase_contrast(self):
self.data -= self.data.min() self.data -= self.data.min()
...@@ -31,4 +34,9 @@ class NormalizedCharacterImage(GrayscaleImage): ...@@ -31,4 +34,9 @@ class NormalizedCharacterImage(GrayscaleImage):
cropper.crop_to_letter(self) cropper.crop_to_letter(self)
def resize(self): def resize(self):
GrayscaleImage.resize(self, self.size) """Resize the image to a fixed height."""
if self.height == None:
return
h, w = self.data.shape
GrayscaleImage.resize(self, (self.height, self.height * w / h))
#!/usr/bin/python #!/usr/bin/python
from cPickle import load from os import listdir
from os.path import exists
from cPickle import load, dump
from sys import argv, exit
from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage
from Character import Character
from Classifier import Classifier from Classifier import Classifier
if len(argv) < 3:
print 'Usage: python %s NEIGHBOURS BLUR_SCALE' % argv[0]
exit(1)
neighbours = int(argv[1])
blur_scale = float(argv[2])
suffix = '_%s_%s' % (blur_scale, neighbours)
chars_file = 'characters%s.dat' % suffix
learning_set_file = 'learning_set%s.dat' % suffix
test_set_file = 'test_set%s.dat' % suffix
classifier_file = 'classifier%s.dat' % suffix
results_file = 'results%s.txt' % suffix
# Load characters
if exists(chars_file):
print 'Loading characters...'
chars = load(open(chars_file, 'r'))
else:
print 'Going to generate character objects...'
chars = []
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=blur_scale, height=42)
#imshow(norm.data, cmap='gray'); show()
character = Character(char, [], norm)
character.get_single_cell_feature_vector(neighbours)
chars.append(character)
print char
print 'Saving characters...'
dump(chars, open(chars_file, 'w+'))
# Load learning set and test set
if exists(learning_set_file):
print 'Loading learning set...'
learning_set = load(open(learning_set_file, 'r'))
print 'Learning set:', [c.value for c in learning_set]
print 'Loading test set...'
test_set = load(open(test_set_file, 'r'))
print 'Test set:', [c.value for c in test_set]
else:
print 'Going to generate learning set and test set...'
learning_set = []
test_set = []
learned = []
for char in chars:
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 '\nTest set:', [c.value for c in test_set]
print '\nSaving learning set...'
dump(learning_set, file(learning_set_file, 'w+'))
print 'Saving test set...'
dump(test_set, file(test_set_file, 'w+'))
# Perform a grid-search to find the optimal values for C and gamma
C = [float(2 ** p) for p in xrange(-5, 16, 2)] C = [float(2 ** p) for p in xrange(-5, 16, 2)]
Y = [float(2 ** p) for p in xrange(-15, 4, 2)] Y = [float(2 ** p) for p in xrange(-15, 4, 2)]
best_classifier = None
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 = [] results = []
best = (0,) best = (0,)
i = 0 i = 0
for c in C: for c in C:
for y in Y: for y in Y:
classifier = Classifier(c=c, gamma=y) classifier = Classifier(c=c, gamma=y, neighbours=neighbours)
classifier.train(learning_set) classifier.train(learning_set)
result = classifier.test(test_set) result = classifier.test(test_set)
...@@ -33,22 +99,30 @@ for c in C: ...@@ -33,22 +99,30 @@ for c in C:
% (i, len(C) * len(Y), c, y, int(round(result * 100))) % (i, len(C) * len(Y), c, y, int(round(result * 100)))
i = 0 i = 0
s = ' c\y'
print '\n c\y',
for y in Y: for y in Y:
print '| %f' % y, s += '| %f' % y
print s += '\n'
for c in C: for c in C:
print ' %7s' % c, s += ' %7s' % c
for y in Y: for y in Y:
print '| %8d' % int(round(results[i] * 100)), s += '| %8d' % int(round(results[i] * 100))
i += 1 i += 1
print s += '\n'
s += '\nBest result: %.3f%% for C = %f and gamma = %f' % best[:3]
print 'Saving results...'
f = open(results_file, 'w+')
f.write(s + '\n')
f.close()
print '\nBest result: %.3f%% for C = %f and gamma = %f' % best[:3] print 'Saving best classifier...'
best[3].save(classifier_file)
best[3].save('classifier.dat') print '\n' + s
#!/usr/bin/python #!/usr/bin/python
from os import listdir from os import listdir
from cPickle import dump from cPickle import dump
from pylab import imshow, show from sys import argv, exit
from GrayscaleImage import GrayscaleImage from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage from NormalizedCharacterImage import NormalizedCharacterImage
from Character import Character from Character import Character
if len(argv) < 4:
print 'Usage: python %s FILE_SUFFIX BLUR_SCALE NEIGHBOURS' % argv[0]
exit(1)
c = [] c = []
for char in sorted(listdir('../images/LearningSet')): for char in sorted(listdir('../images/LearningSet')):
for image in sorted(listdir('../images/LearningSet/' + char)): for image in sorted(listdir('../images/LearningSet/' + char)):
f = '../images/LearningSet/' + char + '/' + image f = '../images/LearningSet/' + char + '/' + image
image = GrayscaleImage(f) image = GrayscaleImage(f)
norm = NormalizedCharacterImage(image, blur=1, size=(48, 36)) norm = NormalizedCharacterImage(image, blur=float(argv[2]), height=42)
#imshow(norm.data, cmap='gray') #from pylab import imshow, show
#show() #imshow(norm.data, cmap='gray'); show()
character = Character(char, [], norm) character = Character(char, [], norm)
character.get_single_cell_feature_vector() character.get_single_cell_feature_vector(int(argv[3]))
c.append(character) c.append(character)
print char print char
dump(c, open('characters.dat', 'w+')) print 'Saving characters...'
dump(c, open('characters%s.dat' % argv[1], 'w+'))
#!/usr/bin/python
from cPickle import dump, load
from sys import argv, exit
if len(argv) < 2:
print 'Usage: python %s FILE_SUFFIX' % argv[0]
exit(1)
print 'Loading characters...'
chars = load(file('characters%s.dat' % argv[1], 'r'))
learning_set = []
test_set = []
#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]
learned = []
for char in chars:
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 '\nTest set:', [c.value for c in test_set]
print '\nSaving learning set...'
dump(learning_set, file('learning_set%s.dat' % argv[1], 'w+'))
print 'Saving test set...'
dump(test_set, file('test_set%s.dat' % argv[1], 'w+'))
#!/usr/bin/python #!/usr/bin/python
from xml_helper_functions import xml_to_LicensePlate
from Classifier import Classifier
from cPickle import dump, load from cPickle import dump, load
chars = load(file('characters.dat', 'r')) from Classifier import Classifier
learning_set = []
test_set = []
#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]
learned = []
for char in chars: if len(argv) < 5:
if learned.count(char.value) == 70: print 'Usage: python %s FILE_SUFFIX C GAMMA NEIGHBOURS' % argv[0]
test_set.append(char) exit(1)
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]
print 'Saving learning set...'
dump(learning_set, file('learning_set.dat', 'w+'))
print 'Saving test set...'
dump(test_set, file('test_set.dat', 'w+'))
#----------------------------------------------------------------
print 'Loading learning set' print 'Loading learning set'
learning_set = load(file('learning_set.dat', 'r')) learning_set = load(file('learning_set%s.dat' % argv[1], 'r'))
# Train the classifier with the learning set # Train the classifier with the learning set
classifier = Classifier(c=512, gamma=.125, cell_size=12) classifier = Classifier(c=float(argv[1]), \
gamma=float(argv[2]), \
neighbours=int(argv[3]))
classifier.train(learning_set) classifier.train(learning_set)
classifier.save('classifier.dat')
print 'Saved classifier'
#----------------------------------------------------------------
print 'Loading classifier'
classifier = Classifier(filename='classifier.dat')
print 'Loading test set' print 'Loading test set'
test_set = load(file('test_set.dat', 'r')) test_set = load(file('test_set%s.dat' % argv[1], 'r'))
l = len(test_set) l = len(test_set)
matches = 0 matches = 0
......
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