Commit 84952000 authored by Jayke Meijer's avatar Jayke Meijer

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

parents 93292816 a68fe0cd
......@@ -6,12 +6,6 @@ class Character:
self.corners = corners
self.image = image
# Testing purposes
def show(self):
from pylab import imshow, show
imshow(self.data, cmap="gray")
show()
def get_feature_vector(self):
pattern = LocalBinaryPatternizer(self.image)
......
from svmutil import svm_train, svm_problem, svm_parameter, svm_predict, \
LINEAR, svm_save_model, svm_load_model
svm_save_model, svm_load_model
from cPickle import dump, load
......@@ -13,7 +13,7 @@ class Classifier:
f.close()
else:
self.param = svm_parameter()
self.param.kernel_type = LINEAR
self.param.kernel_type = 2
self.param.C = c
self.character_map = {}
self.model = None
......
......@@ -3,63 +3,63 @@ from LicensePlate import 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.info' % (i, i, j)
# print 'loading file "%s"' % filename
# plate = LicensePlate(i, j)
#
# if hasattr(plate, 'characters'):
# chars.extend(plate.characters)
# except:
# print 'epic fail'
#
#print 'loaded %d chars' % len(chars)
#
#dump(chars, file('chars', 'w+'))
chars = []
for i in range(9):
for j in range(100):
try:
filename = '%04d/00991_%04d%02d.info' % (i, i, j)
print 'loading file "%s"' % filename
plate = LicensePlate(i, j)
if hasattr(plate, 'characters'):
chars.extend(plate.characters)
except:
print 'epic fail'
print 'loaded %d chars' % len(chars)
dump(chars, file('chars', 'w+'))
#----------------------------------------------------------------
#chars = load(file('chars', 'r'))
#learned = []
#learning_set = []
#test_set = []
#
#for char in chars:
# if learned.count(char.value) > 80:
# test_set.append(char)
# else:
# learning_set.append(char)
# learned.append(char.value)
#
#dump(learning_set, file('learning_set', 'w+'))
#dump(test_set, file('test_set', 'w+'))
chars = load(file('chars', 'r'))
learned = []
learning_set = []
test_set = []
for char in chars:
if learned.count(char.value) > 80:
test_set.append(char)
else:
learning_set.append(char)
learned.append(char.value)
dump(learning_set, file('learning_set', 'w+'))
dump(test_set, file('test_set', 'w+'))
#----------------------------------------------------------------
learning_set = load(file('learning_set', 'r'))
# Train the classifier with the learning set
classifier = Classifier(c=3)
classifier = Classifier(c=30)
classifier.train(learning_set)
#classifier.save('classifier')
classifier.save('classifier')
#----------------------------------------------------------------
#classifier = Classifier(filename='classifier')
#test_set = load(file('test_set', 'r'))
#l = len(test_set)
#matches = 0
#
#for i, char in enumerate(test_set):
# prediction = classifier.classify(char)
#
# if char.value == prediction:
# print ':) ------> Successfully recognized "%s"' % char.value
# matches += 1
# else:
# print ':( Expected character "%s", got "%s"' \
# % (char.value, prediction),
#
# print ' -- %d of %d (%d%% done)' % (i + 1, l, int(100 * (i + 1) / l))
#
#print '\n%d matches (%d%%), %d fails' % (matches, \
# int(100 * matches / len(test_set)), \
# len(test_set) - matches)
classifier = Classifier(filename='classifier')
test_set = load(file('test_set', 'r'))
l = len(test_set)
matches = 0
for i, char in enumerate(test_set):
prediction = classifier.classify(char)
if char.value == prediction:
print ':) ------> Successfully recognized "%s"' % char.value,
matches += 1
else:
print ':( Expected character "%s", got "%s"' \
% (char.value, prediction),
print ' -- %d of %d (%d%% done)' % (i + 1, l, int(100 * (i + 1) / l))
print '\n%d matches (%d%%), %d fails' % (matches, \
int(100 * matches / len(test_set)), \
len(test_set) - matches)
import traceback, os.path
class Error:
def __init__(self, message=None):
stack = traceback.extract_stack()
origin_of_call = stack[0]
where_it_went_wrong = stack[1]
if message:
print message, "\n"
print "Error in", origin_of_call[0], "on line", origin_of_call[1]
print " : ", origin_of_call[3], "\n"
# Inside try function, so -2 lines as exept and Error() are 2 lines
print "Function called in", where_it_went_wrong[0]
print "around line", (where_it_went_wrong[1] - 2), "\n"
\ No newline at end of file
from GrayscaleImage import GrayscaleImage
from scipy.ndimage import convolve1d
from pylab import ceil, zeros, pi, e, exp, sqrt, array
from pylab import ceil, zeros, pi, exp, sqrt, array
class GaussianFilter:
def __init__(self, scale):
self.scale = scale
def gaussian(self, x):
'''Return the value of a 1D Gaussian function for a given x and scale'''
return exp(-(x ** 2 / (2 * self.scale ** 2))) / (sqrt(2 * pi) * self.scale)
"""Return the value of a 1D Gaussian function for a given x."""
return exp(-(x ** 2 / (2 * self.scale ** 2))) \
/ (sqrt(2 * pi) * self.scale)
def get_1d_gaussian_kernel(self):
'''Sample a one-dimensional Gaussian function of scale s'''
"""Sample a one-dimensional Gaussian function of scale s."""
radius = int(ceil(3 * self.scale))
size = 2 * radius + 1
result = zeros(size)
# Sample the Gaussian function
# Sample the Gaussian function
result = array([self.gaussian(x - radius) for x in xrange(size)])
# The sum of all kernel values is equal to one
result /= result.sum()
result /= result.sum()
return result
def get_filtered_copy(self, image):
'''Apply a gaussian blur to an image, to suppress noise.'''
"""Apply a gaussian blur to an image, to suppress noise."""
kernel = self.get_1d_gaussian_kernel()
image = convolve1d(image.data, kernel, axis=0, mode='nearest')
return GrayscaleImage(None, convolve1d(image, kernel, axis=1, mode='nearest'))
def filter(self, image):
kernel = self.get_1d_gaussian_kernel()
image.data = convolve1d(image.data, kernel, axis=0, mode='nearest')
image.data = convolve1d(image.data, kernel, axis=1, mode='nearest')
def get_scale(self):
return self.scale
def set_scale(self, scale):
self.scale = float(scale)
......
from pylab import imshow, imread, show
from scipy.misc import imresize
from matplotlib.pyplot import hist
from scipy.misc import imresize, imsave
......@@ -8,21 +7,21 @@ class GrayscaleImage:
def __init__(self, image_path = None, data = None):
if image_path != None:
self.data = imread(image_path)
extension = image_path.split('.',3)[-1]
extension = image_path.split('.', 3)[-1]
if extension == "jpg":
self.data = self.data[::-1]
self.convert_to_grayscale()
elif data != None:
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:
......@@ -30,47 +29,47 @@ class GrayscaleImage:
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]
def convert_to_grayscale(self):
if len(self.data.shape) > 2:
self.data = self.data[:,:,:3].sum(axis=2) / 3
def crop(self, rectangle):
self.data = self.data[rectangle.y : rectangle.y + rectangle.height,
self.data = self.data[rectangle.y : rectangle.y + rectangle.height,
rectangle.x : rectangle.x + rectangle.width]
def show(self):
imshow(self.data, cmap="gray")
show()
def make_histogram(self):
return hist(self.data)
def resize(self, size): # size is of type float
def resize(self, size): # size is of type float
self.data = imresize(self.data, size)
def get_shape(self):
return self.data.shape
shape = property(get_shape)
def get_width(self):
return self.get_shape()[1]
width = property(get_width)
def get_height(self):
return self.get_shape()[0]
height = property(get_height)
def in_bounds(self, y, x):
return x >= 0 and x < self.width and y >= 0 and y < self.height
def save(self, path):
imsave(path, self.data)
......@@ -4,14 +4,15 @@ class Histogram:
self.bins = [0] * bins
self.min = min
self.max = max
def add(self, number):
bin_index = self.get_bin_index(number)
self.bins[bin_index] += 1
def remove(self, number):
bin_index = self.get_bin_index(number)
self.bins[bin_index] -= 1
def get_bin_index(self, number):
return (number - self.min) / ((self.max - self.min) / len(self.bins))
\ No newline at end of file
return (number - self.min) / ((self.max - self.min) / len(self.bins))
from copy import deepcopy
from Rectangle import Rectangle
from GrayscaleImage import GrayscaleImage
class LetterCropper:
def __init__(self, threshold = 0.9):
self.threshold = threshold
def crop_to_letter(self, image):
self.image = image
self.determine_letter_bounds()
......@@ -24,10 +22,10 @@ class LetterCropper:
if y < min_y: min_y = y
if x > max_x: max_x = x
if y > max_y: max_y = y
self.letter_bounds = Rectangle(
min_x,
min_y,
min_x,
min_y,
max_x - min_x ,
max_y - min_y
)
from pylab import array, zeros, inv, dot, svd, shape, floor
from pylab import array, zeros, inv, dot, svd, floor
from xml.dom.minidom import parse
from Error import Error
from Point import Point
from Character import Character
from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage
'''
Creates a license plate object based on an XML file. The image should be
placed in a folder 'images' the xml file in a folder 'xml'
TODO: perhaps remove non required XML lookups
'''
class LicensePlate:
def __init__(self, folder_nr, file_nr):
......@@ -37,14 +30,14 @@ class LicensePlate:
N = max(y0, y1, y2, y3) - min(y0, y1, y2, y3)
matrix = array([
[x0, y0, 1, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, x0, y0, 1, 0, 0, 0],
[x1, y1, 1, 0, 0, 0, -M*x0, -M*y1, -M],
[ 0, 0, 0, x1, y1, 1, 0, 0, 0],
[x2, y2, 1, 0, 0, 0, -M*x2, -M*y2, -M],
[ 0, 0, 0, x2, y2, 1, -N*x2, -N*y2, -N],
[x3, y3, 1, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, x3, y3, 1, -N*x3, -N*y3, -N]
[x0, y0, 1, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, x0, y0, 1, 0, 0, 0],
[x1, y1, 1, 0, 0, 0, -M * x0, -M * y1, -M],
[ 0, 0, 0, x1, y1, 1, 0, 0, 0],
[x2, y2, 1, 0, 0, 0, -M * x2, -M * y2, -M],
[ 0, 0, 0, x2, y2, 1, -N * x2, -N * y2, -N],
[x3, y3, 1, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, x3, y3, 1, -N * x3, -N * y3, -N]
])
P = inv(self.get_transformation_matrix(matrix))
......@@ -53,7 +46,9 @@ class LicensePlate:
for i in range(0, M):
for j in range(0, N):
or_coor = dot(P, ([[i],[j],[1]]))
or_coor_h = or_coor[1][0] / or_coor[2][0], or_coor[0][0] / or_coor[2][0]
or_coor_h = (or_coor[1][0] / or_coor[2][0],
or_coor[0][0] / or_coor[2][0])
data[j][i] = self.pV(or_coor_h[0], or_coor_h[1])
return data
......@@ -75,9 +70,7 @@ class LicensePlate:
def pV(self, x, y):
image = self.image
'''Get the value of a point x,y in the given image, where x and y are not
necessary integers, so the value is interpolated from its neighbouring
pixels.'''
#Get the value of a point (interpolated x, y) in the given image
if image.in_bounds(x, y):
x_low = floor(x)
x_high = floor(x + 1)
......@@ -161,4 +154,4 @@ class LicensePlate:
if corner.nodeName == "point":
corners.append(Point(corner))
return corners
return corners
\ No newline at end of file
from Histogram import Histogram
from numpy import zeros, byte
from math import ceil
class LocalBinaryPatternizer:
......
from GrayscaleImage import GrayscaleImage
from LocalBinaryPatternizer import LocalBinaryPatternizer
from LetterCropper import LetterCropper
from matplotlib.pyplot import imshow, subplot, show, axis, bar
from numpy import arange
image = GrayscaleImage("../images/test.png")
lbp = LocalBinaryPatternizer(image)
histograms = lbp.create_features_vector()
print histograms
\ No newline at end of file
print histograms
......@@ -4,7 +4,7 @@ from LetterCropper import LetterCropper
from GaussianFilter import GaussianFilter
class NormalizedCharacterImage(GrayscaleImage):
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))
......@@ -22,13 +22,13 @@ class NormalizedCharacterImage(GrayscaleImage):
self.data -= self.data.min()
self.data /= self.data.max()
def gausse_filter(self):
def gausse_filter(self):
filter = GaussianFilter(1.1)
filter.filter(self)
def crop_to_letter(self):
cropper = LetterCropper(0.9)
cropper.crop_to_letter(self)
def resize(self):
GrayscaleImage.resize(self, self.size)
\ No newline at end of file
GrayscaleImage.resize(self, self.size)
class Rectangle:
def __init__(self, x, y, width, height):
self.x = x;
self.y = y;
self.width = width;
self.height = height;
self.x = x
self.y = y
self.width = width
self.height = height
from GrayscaleImage import GrayscaleImage
from NormalizedCharacterImage import NormalizedCharacterImage
from LetterCropper import LetterCropper
from NormalizedCharacterImage import NormalizedCharacterImage
image = GrayscaleImage("../images/test10.png")
normalized_character_image = NormalizedCharacterImage(image)
normalized_character_image.show()
\ No newline at end of file
normalized_character_image.show()
from LicensePlate import LicensePlate
'''
create new LicensePlate object:
i.e you can do
plate = LicensePlate("../XML/test.info") # some xml file from rein
now available:
plate.image
plate.width
plate.height
Are the entire image widht / height and image is the corresponding image file
provided by rein (i.e other folder somewhere)
plate.corners
plate.license_full # the entire license plate as a string so 2334AB
plate.characters # for each character from license_full a Character object
exists, kinda same as the license plate. You have a value
= the character / number
a corners -> i.e list of points (Point objects)
TODO had to go so this text is full of crap maybe, anyway enjoy
'''
plate = LicensePlate("../XML/0000/00991_000000.info") # some xml file from rein
print plate.characters[0].value
#plate.characters[0].show()
\ No newline at end of file
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