Commit 7a67ea01 authored by Taddeus Kroes's avatar Taddeus Kroes

Implemented 5x5 neighbourhood patterns.

parent 2e1b2e8c
*.dat
results.txt
results*.txt
......@@ -7,11 +7,12 @@ class Character:
self.image = image
self.filename = filename
def get_single_cell_feature_vector(self):
def get_single_cell_feature_vector(self, neighbours=5):
if hasattr(self, 'feature'):
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):
pattern = LBP(self.image) if cell_size == None \
......
......@@ -3,8 +3,8 @@ from svmutil import svm_train, svm_problem, svm_parameter, svm_predict, \
class Classifier:
def __init__(self, c=None, gamma=None, filename=None, cell_size=12):
self.cell_size = cell_size
def __init__(self, c=None, gamma=None, filename=None, neighbours=3):
self.neighbours = neighbours
if filename:
# If a filename is given, load a model from the given filename
......@@ -34,7 +34,7 @@ class Classifier:
% (char.value, i + 1, l, int(100 * (i + 1) / l))
classes.append(float(ord(char.value)))
#features.append(char.get_feature_vector())
char.get_single_cell_feature_vector()
char.get_single_cell_feature_vector(self.neighbours)
features.append(char.feature)
problem = svm_problem(classes, features)
......@@ -56,7 +56,7 @@ class Classifier:
"""Classify a character object, return its value."""
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()
character.get_single_cell_feature_vector(self.neighbours)
p = svm_predict([true_value], [character.feature], self.model)
prediction_class = int(p[0][0])
......
......@@ -3,9 +3,13 @@ from math import ceil
class LocalBinaryPatternizer:
def __init__(self, image, cell_size=16):
def __init__(self, image, cell_size=16, neighbours=3):
self.cell_size = cell_size
self.image = image
self.pattern_callback, self.bins = {
3: (self.pattern_3x3, 256),
5: (self.pattern_5x5, 4096)
}[neighbours]
def setup_histograms(self):
cells_in_width = int(ceil(self.image.width / float(self.cell_size)))
......@@ -16,9 +20,9 @@ class LocalBinaryPatternizer:
self.histograms.append([])
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) \
| (self.is_pixel_darker(y - 1, x , value) << 6) \
| (self.is_pixel_darker(y - 1, x + 1, value) << 5) \
......@@ -26,7 +30,21 @@ class LocalBinaryPatternizer:
| (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)
| (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):
'''Walk around the pixels in clokwise order, shifting 1 bit less at
......@@ -36,7 +54,7 @@ class LocalBinaryPatternizer:
for y, x, value in self.image:
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()
......@@ -55,15 +73,14 @@ class LocalBinaryPatternizer:
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)
h = Histogram(self.bins, 0, self.bins)
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()
......
......@@ -5,19 +5,22 @@ 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, height=None, blur=1.1):
if image != None:
GrayscaleImage.__init__(self, data=deepcopy(image.data))
elif data != None:
GrayscaleImage.__init__(self, data=deepcopy(data))
self.blur = blur
self.crop_threshold = crop_threshold
self.size = size
self.gaussian_filter()
self.increase_contrast()
#self.crop_threshold = crop_threshold
#self.crop_to_letter()
#self.resize()
self.height = height
self.resize()
def increase_contrast(self):
self.data -= self.data.min()
......@@ -31,4 +34,9 @@ class NormalizedCharacterImage(GrayscaleImage):
cropper.crop_to_letter(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
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
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)]
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 = []
best = (0,)
i = 0
for c in C:
for y in Y:
classifier = Classifier(c=c, gamma=y)
classifier = Classifier(c=c, gamma=y, neighbours=neighbours)
classifier.train(learning_set)
result = classifier.test(test_set)
......@@ -33,22 +99,30 @@ for c in C:
% (i, len(C) * len(Y), c, y, int(round(result * 100)))
i = 0
s = ' c\y'
print '\n c\y',
for y in Y:
print '| %f' % y,
s += '| %f' % y
print
s += '\n'
for c in C:
print ' %7s' % c,
s += ' %7s' % c
for y in Y:
print '| %8d' % int(round(results[i] * 100)),
s += '| %8d' % int(round(results[i] * 100))
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)
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
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